Просмотр исходного кода

Merge pull request #10406 from growilabs/support/biome-organize-imports

support: Apply Biome and organize imports
mergify[bot] 5 месяцев назад
Родитель
Сommit
8de4f1fdc7
100 измененных файлов с 618 добавлено и 453 удалено
  1. 4 0
      .vscode/settings.json
  2. 0 1
      apps/app/bin/openapi/generate-operation-ids/cli.spec.ts
  3. 0 1
      apps/app/bin/print-memory-consumption.ts
  4. 0 1
      apps/app/playwright.config.ts
  5. 2 3
      apps/app/src/features/external-user-group/client/components/ExternalUserGroup/ExternalUserGroupManagement.tsx
  6. 0 1
      apps/app/src/features/external-user-group/client/components/ExternalUserGroup/KeycloakGroupSyncSettingsForm.tsx
  7. 0 1
      apps/app/src/features/external-user-group/client/components/ExternalUserGroup/LdapGroupManagement.tsx
  8. 0 1
      apps/app/src/features/external-user-group/client/components/ExternalUserGroup/LdapGroupSyncSettingsForm.tsx
  9. 0 1
      apps/app/src/features/external-user-group/client/components/ExternalUserGroup/SyncExecution.tsx
  10. 0 1
      apps/app/src/features/external-user-group/server/models/external-user-group-relation.ts
  11. 1 0
      apps/app/src/features/external-user-group/server/routes/apiv3/external-user-group-relation.ts
  12. 0 1
      apps/app/src/features/external-user-group/server/service/keycloak-user-group-sync.ts
  13. 0 1
      apps/app/src/features/external-user-group/server/service/ldap-user-group-sync.ts
  14. 1 2
      apps/app/src/features/growi-plugin/client/components/Admin/PluginsExtensionPageContents/PluginCard.tsx
  15. 2 3
      apps/app/src/features/growi-plugin/client/components/Admin/PluginsExtensionPageContents/PluginDeleteModal.tsx
  16. 1 1
      apps/app/src/features/growi-plugin/client/components/Admin/PluginsExtensionPageContents/PluginInstallerForm.tsx
  17. 1 3
      apps/app/src/features/growi-plugin/client/components/Admin/PluginsExtensionPageContents/PluginsExtensionPageContents.tsx
  18. 1 0
      apps/app/src/features/growi-plugin/server/routes/apiv3/admin/index.ts
  19. 0 1
      apps/app/src/features/growi-plugin/server/services/growi-plugin/growi-plugin.integ.ts
  20. 0 1
      apps/app/src/features/growi-plugin/server/services/growi-plugin/growi-plugin.ts
  21. 1 1
      apps/app/src/features/mermaid/components/MermaidViewer.tsx
  22. 0 1
      apps/app/src/features/opentelemetry/server/anonymization/handlers/index.ts
  23. 0 1
      apps/app/src/features/opentelemetry/server/anonymization/handlers/page-access-handler.spec.ts
  24. 0 1
      apps/app/src/features/opentelemetry/server/anonymization/handlers/page-api-handler.spec.ts
  25. 0 1
      apps/app/src/features/opentelemetry/server/anonymization/handlers/page-listing-api-handler.spec.ts
  26. 0 1
      apps/app/src/features/opentelemetry/server/anonymization/handlers/search-api-handler.spec.ts
  27. 0 1
      apps/app/src/features/opentelemetry/server/custom-resource-attributes/os-resource-attributes.ts
  28. 1 1
      apps/app/src/features/page-bulk-export/client/components/PageBulkExportSelectModal.tsx
  29. 0 1
      apps/app/src/features/page-bulk-export/server/service/check-page-bulk-export-job-in-progress-cron.ts
  30. 0 1
      apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-clean-up-cron.integ.ts
  31. 1 1
      apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-clean-up-cron.ts
  32. 0 1
      apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron/index.ts
  33. 0 1
      apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron/request-pdf-converter.ts
  34. 1 0
      apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron/steps/compress-and-upload.ts
  35. 1 0
      apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron/steps/create-page-snapshots-async.ts
  36. 1 0
      apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron/steps/export-pages-to-fs-async.ts
  37. 0 1
      apps/app/src/features/rate-limiter/middleware/consume-points.ts
  38. 0 1
      apps/app/src/features/rate-limiter/middleware/factory.ts
  39. 1 1
      apps/app/src/features/search/client/components/SearchHelp.tsx
  40. 1 2
      apps/app/src/features/search/client/components/SearchMethodMenuItem.tsx
  41. 2 3
      apps/app/src/features/search/client/components/SearchModal.tsx
  42. 1 2
      apps/app/src/features/search/client/components/SearchResultMenuItem.tsx
  43. 0 1
      apps/app/src/features/search/client/stores/search.ts
  44. 1 0
      apps/app/src/features/templates/server/routes/apiv3/index.ts
  45. 0 1
      apps/app/src/interfaces/renderer-options.ts
  46. 1 1
      apps/app/src/interfaces/ui.ts
  47. 1 1
      apps/app/src/stores-universal/ui.tsx
  48. 3 2
      apps/app/src/utils/logger/index.ts
  49. 0 1
      apps/app/src/utils/page-delete-config.test.ts
  50. 1 0
      apps/app/test/integration/service/search/search-service.test.js
  51. 1 0
      apps/app/test/integration/service/user-groups.test.ts
  52. 1 0
      apps/app/test/integration/service/v5.page.test.ts
  53. 1 0
      apps/app/test/integration/service/v5.public-page.test.ts
  54. 1 0
      apps/pdf-converter/src/controllers/pdf.spec.ts
  55. 1 0
      apps/pdf-converter/src/controllers/pdf.ts
  56. 0 1
      apps/pdf-converter/src/service/pdf-convert.ts
  57. 0 1
      apps/slackbot-proxy/src/controllers/slack.ts
  58. 18 2
      biome.json
  59. 1 0
      package.json
  60. 0 1
      packages/core/src/models/serializers/attachment-serializer.ts
  61. 1 1
      packages/core/src/utils/page-path-utils/index.ts
  62. 0 1
      packages/core/src/utils/page-utils.ts
  63. 0 1
      packages/core/vite.config.ts
  64. 1 2
      packages/editor/.eslintignore
  65. 0 13
      packages/editor/.eslintrc.cjs
  66. 1 1
      packages/editor/package.json
  67. 59 45
      packages/editor/src/client/components-internal/CodeMirrorEditor/CodeMirrorEditor.tsx
  68. 18 24
      packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/AttachmentsDropdownItem.tsx
  69. 35 20
      packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/AttachmentsDropup.tsx
  70. 8 4
      packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/DiagramButton.tsx
  71. 20 20
      packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/EmojiButton.tsx
  72. 11 7
      packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/LinkEditButton.tsx
  73. 8 5
      packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/TableButton.tsx
  74. 11 5
      packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/TemplateButton.tsx
  75. 75 25
      packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/TextFormatTools.tsx
  76. 25 14
      packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/Toolbar.tsx
  77. 46 28
      packages/editor/src/client/components-internal/playground/Playground.tsx
  78. 10 8
      packages/editor/src/client/components-internal/playground/PlaygroundController.tsx
  79. 2 2
      packages/editor/src/client/components-internal/playground/Preview.tsx
  80. 7 3
      packages/editor/src/client/components-internal/playground/controller/KeymapControl.tsx
  81. 6 6
      packages/editor/src/client/components-internal/playground/controller/OutlineSecondaryButtons.tsx
  82. 7 3
      packages/editor/src/client/components-internal/playground/controller/PasteModeControl.tsx
  83. 7 1
      packages/editor/src/client/components-internal/playground/controller/SetCaretLineRow.tsx
  84. 7 3
      packages/editor/src/client/components-internal/playground/controller/ThemeControl.tsx
  85. 17 4
      packages/editor/src/client/components-internal/playground/controller/UnifiedMergeViewControl.tsx
  86. 12 20
      packages/editor/src/client/components/CodeMirrorEditorComment.tsx
  87. 39 32
      packages/editor/src/client/components/CodeMirrorEditorMain.tsx
  88. 16 17
      packages/editor/src/client/components/CodeMirrorEditorReadOnly.tsx
  89. 7 8
      packages/editor/src/client/components/diff/CodeMirrorEditorDiff.tsx
  90. 5 6
      packages/editor/src/client/components/diff/MergeViewer.tsx
  91. 3 1
      packages/editor/src/client/services-internal/editor-theme/index.ts
  92. 9 1
      packages/editor/src/client/services-internal/editor-theme/original-dark.ts
  93. 17 3
      packages/editor/src/client/services-internal/editor-theme/original-light.ts
  94. 24 17
      packages/editor/src/client/services-internal/extensions/emojiAutocompletionSettings.ts
  95. 3 7
      packages/editor/src/client/services-internal/extensions/setDataLine.ts
  96. 1 1
      packages/editor/src/client/services-internal/file-dropzone/index.ts
  97. 3 4
      packages/editor/src/client/services-internal/file-dropzone/use-file-dropzone/FileDropzoneOverlay.tsx
  98. 27 25
      packages/editor/src/client/services-internal/file-dropzone/use-file-dropzone/use-file-dropzone.ts
  99. 7 3
      packages/editor/src/client/services-internal/keymaps/index.ts
  100. 8 3
      packages/editor/src/client/services-internal/link-util/markdown-link-util.ts

+ 4 - 0
.vscode/settings.json

@@ -11,6 +11,10 @@
     "editor.defaultFormatter": "biomejs.biome"
   },
 
+  "[json]": {
+    "editor.defaultFormatter": "biomejs.biome"
+  },
+
   // use vscode-stylelint
   // see https://github.com/stylelint/vscode-stylelint
   "stylelint.validate": ["css", "less", "scss"],

+ 0 - 1
apps/app/bin/openapi/generate-operation-ids/cli.spec.ts

@@ -1,5 +1,4 @@
 import { writeFileSync } from 'node:fs';
-
 import { beforeEach, describe, expect, it, vi } from 'vitest';
 
 import { generateOperationIds } from './generate-operation-ids';

+ 0 - 1
apps/app/bin/print-memory-consumption.ts

@@ -12,7 +12,6 @@
  */
 
 import { get } from 'node:http';
-
 import WebSocket from 'ws';
 
 interface MemoryInfo {

+ 0 - 1
apps/app/playwright.config.ts

@@ -1,6 +1,5 @@
 import fs from 'node:fs';
 import path from 'node:path';
-
 import { defineConfig, devices, type Project } from '@playwright/test';
 
 const authFile = path.resolve(__dirname, './playwright/.auth/admin.json');

+ 2 - 3
apps/app/src/features/external-user-group/client/components/ExternalUserGroup/ExternalUserGroupManagement.tsx

@@ -1,7 +1,7 @@
-import type { IGrantedGroup } from '@growi/core';
-import { GroupType, getIdForRef } from '@growi/core';
 import type { FC } from 'react';
 import { useCallback, useMemo, useState } from 'react';
+import type { IGrantedGroup } from '@growi/core';
+import { GroupType, getIdForRef } from '@growi/core';
 import { useTranslation } from 'react-i18next';
 import { TabContent, TabPane } from 'reactstrap';
 
@@ -21,7 +21,6 @@ import {
   useSWRxExternalUserGroupList,
   useSWRxExternalUserGroupRelationList,
 } from '../../stores/external-user-group';
-
 import { KeycloakGroupManagement } from './KeycloakGroupManagement';
 import { LdapGroupManagement } from './LdapGroupManagement';
 

+ 0 - 1
apps/app/src/features/external-user-group/client/components/ExternalUserGroup/KeycloakGroupSyncSettingsForm.tsx

@@ -1,6 +1,5 @@
 import type { FC } from 'react';
 import { useCallback, useEffect, useState } from 'react';
-
 import { useTranslation } from 'react-i18next';
 
 import { apiv3Put } from '~/client/util/apiv3-client';

+ 0 - 1
apps/app/src/features/external-user-group/client/components/ExternalUserGroup/LdapGroupManagement.tsx

@@ -1,6 +1,5 @@
 import type { FC } from 'react';
 import { type JSX, useCallback, useEffect, useState } from 'react';
-
 import { useTranslation } from 'react-i18next';
 
 import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';

+ 0 - 1
apps/app/src/features/external-user-group/client/components/ExternalUserGroup/LdapGroupSyncSettingsForm.tsx

@@ -1,6 +1,5 @@
 import type { FC } from 'react';
 import { useCallback, useEffect, useState } from 'react';
-
 import { useTranslation } from 'react-i18next';
 
 import { apiv3Put } from '~/client/util/apiv3-client';

+ 0 - 1
apps/app/src/features/external-user-group/client/components/ExternalUserGroup/SyncExecution.tsx

@@ -1,6 +1,5 @@
 import type { FC, JSX } from 'react';
 import { useCallback, useEffect, useState } from 'react';
-
 import { useTranslation } from 'react-i18next';
 import { Modal, ModalBody, ModalHeader } from 'reactstrap';
 

+ 0 - 1
apps/app/src/features/external-user-group/server/models/external-user-group-relation.ts

@@ -6,7 +6,6 @@ import UserGroupRelation from '~/server/models/user-group-relation';
 
 import { getOrCreateModel } from '../../../../server/util/mongoose-utils';
 import type { IExternalUserGroupRelation } from '../../interfaces/external-user-group';
-
 import type { ExternalUserGroupDocument } from './external-user-group';
 
 export interface ExternalUserGroupRelationDocument

+ 1 - 0
apps/app/src/features/external-user-group/server/routes/apiv3/external-user-group-relation.ts

@@ -1,6 +1,7 @@
 import { SCOPE } from '@growi/core/dist/interfaces';
 import { ErrorV3 } from '@growi/core/dist/models';
 import type { Request, Router } from 'express';
+
 import type { IExternalUserGroupRelationHasId } from '~/features/external-user-group/interfaces/external-user-group';
 import ExternalUserGroupRelation from '~/features/external-user-group/server/models/external-user-group-relation';
 import type Crowi from '~/server/crowi';

+ 0 - 1
apps/app/src/features/external-user-group/server/service/keycloak-user-group-sync.ts

@@ -12,7 +12,6 @@ import type {
   ExternalUserInfo,
 } from '../../interfaces/external-user-group';
 import { ExternalGroupProviderType } from '../../interfaces/external-user-group';
-
 import ExternalUserGroupSyncService from './external-user-group-sync';
 
 const logger = loggerFactory('growi:service:keycloak-user-group-sync-service');

+ 0 - 1
apps/app/src/features/external-user-group/server/service/ldap-user-group-sync.ts

@@ -14,7 +14,6 @@ import {
   ExternalGroupProviderType,
   LdapGroupMembershipAttributeType,
 } from '../../interfaces/external-user-group';
-
 import ExternalUserGroupSyncService from './external-user-group-sync';
 
 const logger = loggerFactory('growi:service:ldap-user-group-sync-service');

+ 1 - 2
apps/app/src/features/growi-plugin/client/components/Admin/PluginsExtensionPageContents/PluginCard.tsx

@@ -1,7 +1,6 @@
+import React, { type JSX, useState } from 'react';
 import Link from 'next/link';
-
 import { useTranslation } from 'next-i18next';
-import React, { type JSX, useState } from 'react';
 
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { toastError, toastSuccess } from '~/client/util/toastr';

+ 2 - 3
apps/app/src/features/growi-plugin/client/components/Admin/PluginsExtensionPageContents/PluginDeleteModal.tsx

@@ -1,8 +1,7 @@
-import Link from 'next/link';
-
-import { useTranslation } from 'next-i18next';
 import type React from 'react';
 import { useCallback } from 'react';
+import Link from 'next/link';
+import { useTranslation } from 'next-i18next';
 import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
 
 import { apiv3Delete } from '~/client/util/apiv3-client';

+ 1 - 1
apps/app/src/features/growi-plugin/client/components/Admin/PluginsExtensionPageContents/PluginInstallerForm.tsx

@@ -1,5 +1,5 @@
-import { useTranslation } from 'next-i18next';
 import React, { type JSX, useCallback } from 'react';
+import { useTranslation } from 'next-i18next';
 
 import { apiv3Post } from '~/client/util/apiv3-client';
 import { toastError, toastSuccess } from '~/client/util/toastr';

+ 1 - 3
apps/app/src/features/growi-plugin/client/components/Admin/PluginsExtensionPageContents/PluginsExtensionPageContents.tsx

@@ -1,14 +1,12 @@
+import React, { type JSX } from 'react';
 import dynamic from 'next/dynamic';
-
 import { useTranslation } from 'next-i18next';
-import React, { type JSX } from 'react';
 import { Spinner } from 'reactstrap';
 
 import {
   usePluginDeleteModal,
   useSWRxAdminPlugins,
 } from '../../../stores/admin-plugins';
-
 import { PluginCard } from './PluginCard';
 import { PluginInstallerForm } from './PluginInstallerForm';
 

+ 1 - 0
apps/app/src/features/growi-plugin/server/routes/apiv3/admin/index.ts

@@ -3,6 +3,7 @@ import type { Request, Router } from 'express';
 import express from 'express';
 import { body, query } from 'express-validator';
 import mongoose from 'mongoose';
+
 import type Crowi from '~/server/crowi';
 import { accessTokenParser } from '~/server/middlewares/access-token-parser';
 import type { ApiV3Response } from '~/server/routes/apiv3/interfaces/apiv3-response';

+ 0 - 1
apps/app/src/features/growi-plugin/server/services/growi-plugin/growi-plugin.integ.ts

@@ -3,7 +3,6 @@ import path from 'path';
 
 import { PLUGIN_STORING_PATH } from '../../consts';
 import { GrowiPlugin } from '../../models';
-
 import { growiPluginService } from './growi-plugin';
 
 describe('Installing a GROWI template plugin', () => {

+ 0 - 1
apps/app/src/features/growi-plugin/server/services/growi-plugin/growi-plugin.ts

@@ -23,7 +23,6 @@ import type {
 import { PLUGIN_EXPRESS_STATIC_DIR, PLUGIN_STORING_PATH } from '../../consts';
 import { GrowiPlugin } from '../../models';
 import { GitHubUrl } from '../../models/vo/github-url';
-
 import { generateTemplatePluginMeta } from './generate-template-plugin-meta';
 import { generateThemePluginMeta } from './generate-theme-plugin-meta';
 

+ 1 - 1
apps/app/src/features/mermaid/components/MermaidViewer.tsx

@@ -1,5 +1,5 @@
-import mermaid from 'mermaid';
 import React, { type JSX, useEffect, useRef } from 'react';
+import mermaid from 'mermaid';
 import { v7 as uuidV7 } from 'uuid';
 
 import { useNextThemes } from '~/stores-universal/use-next-themes';

+ 0 - 1
apps/app/src/features/opentelemetry/server/anonymization/handlers/index.ts

@@ -1,5 +1,4 @@
 import type { AnonymizationModule } from '../interfaces/anonymization-module';
-
 import { pageAccessModule } from './page-access-handler';
 import { pageApiModule } from './page-api-handler';
 import { pageListingApiModule } from './page-listing-api-handler';

+ 0 - 1
apps/app/src/features/opentelemetry/server/anonymization/handlers/page-access-handler.spec.ts

@@ -1,5 +1,4 @@
 import type { IncomingMessage } from 'node:http';
-
 import { describe, expect, it } from 'vitest';
 
 import { pageAccessModule } from './page-access-handler';

+ 0 - 1
apps/app/src/features/opentelemetry/server/anonymization/handlers/page-api-handler.spec.ts

@@ -1,5 +1,4 @@
 import type { IncomingMessage } from 'node:http';
-
 import { beforeEach, describe, expect, it } from 'vitest';
 
 import { pageApiModule } from './page-api-handler';

+ 0 - 1
apps/app/src/features/opentelemetry/server/anonymization/handlers/page-listing-api-handler.spec.ts

@@ -1,5 +1,4 @@
 import type { IncomingMessage } from 'node:http';
-
 import { beforeEach, describe, expect, it } from 'vitest';
 
 import { pageListingApiModule } from './page-listing-api-handler';

+ 0 - 1
apps/app/src/features/opentelemetry/server/anonymization/handlers/search-api-handler.spec.ts

@@ -1,5 +1,4 @@
 import type { IncomingMessage } from 'node:http';
-
 import { beforeEach, describe, expect, it } from 'vitest';
 
 import { searchApiModule } from './search-api-handler';

+ 0 - 1
apps/app/src/features/opentelemetry/server/custom-resource-attributes/os-resource-attributes.ts

@@ -1,5 +1,4 @@
 import * as os from 'node:os';
-
 import type { Attributes } from '@opentelemetry/api';
 
 import loggerFactory from '~/utils/logger';

+ 1 - 1
apps/app/src/features/page-bulk-export/client/components/PageBulkExportSelectModal.tsx

@@ -1,6 +1,6 @@
+import { type JSX, useState } from 'react';
 import { format } from 'date-fns/format';
 import { useTranslation } from 'next-i18next';
-import { type JSX, useState } from 'react';
 import { Modal, ModalBody, ModalHeader } from 'reactstrap';
 
 import { apiv3Post } from '~/client/util/apiv3-client';

+ 0 - 1
apps/app/src/features/page-bulk-export/server/service/check-page-bulk-export-job-in-progress-cron.ts

@@ -4,7 +4,6 @@ import loggerFactory from '~/utils/logger';
 
 import { PageBulkExportJobInProgressStatus } from '../../interfaces/page-bulk-export';
 import PageBulkExportJob from '../models/page-bulk-export-job';
-
 import { pageBulkExportJobCronService } from './page-bulk-export-job-cron';
 
 const logger = loggerFactory(

+ 0 - 1
apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-clean-up-cron.integ.ts

@@ -8,7 +8,6 @@ import {
   PageBulkExportJobStatus,
 } from '../../interfaces/page-bulk-export';
 import PageBulkExportJob from '../models/page-bulk-export-job';
-
 import instanciatePageBulkExportJobCleanUpCronService, {
   pageBulkExportJobCleanUpCronService,
 } from './page-bulk-export-job-clean-up-cron';

+ 1 - 1
apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-clean-up-cron.ts

@@ -1,4 +1,5 @@
 import type { HydratedDocument } from 'mongoose';
+
 import { SupportedAction } from '~/interfaces/activity';
 import type Crowi from '~/server/crowi';
 import { configManager } from '~/server/service/config-manager';
@@ -11,7 +12,6 @@ import {
 } from '../../interfaces/page-bulk-export';
 import type { PageBulkExportJobDocument } from '../models/page-bulk-export-job';
 import PageBulkExportJob from '../models/page-bulk-export-job';
-
 import { pageBulkExportJobCronService } from './page-bulk-export-job-cron';
 
 const logger = loggerFactory(

+ 0 - 1
apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron/index.ts

@@ -23,7 +23,6 @@ import {
 import type { PageBulkExportJobDocument } from '../../models/page-bulk-export-job';
 import PageBulkExportJob from '../../models/page-bulk-export-job';
 import PageBulkExportPageSnapshot from '../../models/page-bulk-export-page-snapshot';
-
 import {
   BulkExportJobExpiredError,
   BulkExportJobStreamDestroyedByCleanupError,

+ 0 - 1
apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron/request-pdf-converter.ts

@@ -9,7 +9,6 @@ import { configManager } from '~/server/service/config-manager';
 import { PageBulkExportJobStatus } from '../../../interfaces/page-bulk-export';
 import type { PageBulkExportJobDocument } from '../../models/page-bulk-export-job';
 import PageBulkExportPageSnapshot from '../../models/page-bulk-export-page-snapshot';
-
 import { BulkExportJobExpiredError } from './errors';
 
 /**

+ 1 - 0
apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron/steps/compress-and-upload.ts

@@ -8,6 +8,7 @@ import type { IAttachmentDocument } from '~/server/models/attachment';
 import { Attachment } from '~/server/models/attachment';
 import type { FileUploader } from '~/server/service/file-uploader';
 import loggerFactory from '~/utils/logger';
+
 import type { PageBulkExportJobDocument } from '../../../models/page-bulk-export-job';
 import type { IPageBulkExportJobCronService } from '..';
 

+ 1 - 0
apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron/steps/create-page-snapshots-async.ts

@@ -7,6 +7,7 @@ import mongoose from 'mongoose';
 import { PageBulkExportJobStatus } from '~/features/page-bulk-export/interfaces/page-bulk-export';
 import { SupportedAction } from '~/interfaces/activity';
 import type { PageDocument, PageModel } from '~/server/models/page';
+
 import type { PageBulkExportJobDocument } from '../../../models/page-bulk-export-job';
 import PageBulkExportJob from '../../../models/page-bulk-export-job';
 import PageBulkExportPageSnapshot from '../../../models/page-bulk-export-page-snapshot';

+ 1 - 0
apps/app/src/features/page-bulk-export/server/service/page-bulk-export-job-cron/steps/export-pages-to-fs-async.ts

@@ -16,6 +16,7 @@ import {
   PageBulkExportFormat,
   PageBulkExportJobStatus,
 } from '~/features/page-bulk-export/interfaces/page-bulk-export';
+
 import type { PageBulkExportJobDocument } from '../../../models/page-bulk-export-job';
 import type { PageBulkExportPageSnapshotDocument } from '../../../models/page-bulk-export-page-snapshot';
 import PageBulkExportPageSnapshot from '../../../models/page-bulk-export-page-snapshot';

+ 0 - 1
apps/app/src/features/rate-limiter/middleware/consume-points.ts

@@ -1,7 +1,6 @@
 import type { RateLimiterRes } from 'rate-limiter-flexible';
 
 import { DEFAULT_MAX_REQUESTS, type IApiRateLimitConfig } from '../config';
-
 import { rateLimiterFactory } from './rate-limiter-factory';
 
 export const consumePoints = async (

+ 0 - 1
apps/app/src/features/rate-limiter/middleware/factory.ts

@@ -10,7 +10,6 @@ import {
   type IApiRateLimitConfig,
 } from '../config';
 import { generateApiRateLimitConfig } from '../utils/config-generator';
-
 import { consumePoints } from './consume-points';
 
 const logger = loggerFactory('growi:middleware:api-rate-limit');

+ 1 - 1
apps/app/src/features/search/client/components/SearchHelp.tsx

@@ -1,5 +1,5 @@
-import { useTranslation } from 'next-i18next';
 import React, { type JSX, useState } from 'react';
+import { useTranslation } from 'next-i18next';
 import { Collapse } from 'reactstrap';
 
 export const SearchHelp = (): JSX.Element => {

+ 1 - 2
apps/app/src/features/search/client/components/SearchMethodMenuItem.tsx

@@ -1,11 +1,10 @@
+import React, { type JSX } from 'react';
 import { DevidedPagePath } from '@growi/core/dist/models';
 import { useTranslation } from 'next-i18next';
-import React, { type JSX } from 'react';
 
 import { useCurrentPagePath } from '~/stores/page';
 
 import type { GetItemProps } from '../interfaces/downshift';
-
 import { SearchMenuItem } from './SearchMenuItem';
 
 type Props = {

+ 2 - 3
apps/app/src/features/search/client/components/SearchModal.tsx

@@ -1,15 +1,14 @@
+import React, { type JSX, useCallback, useEffect, useState } from 'react';
+import { useRouter } from 'next/router';
 import Downshift, {
   type DownshiftState,
   type StateChangeOptions,
 } from 'downshift';
-import { useRouter } from 'next/router';
-import React, { type JSX, useCallback, useEffect, useState } from 'react';
 import { Modal, ModalBody } from 'reactstrap';
 
 import { isIncludeAiMenthion, removeAiMenthion } from '../../utils/ai';
 import type { DownshiftItem } from '../interfaces/downshift';
 import { useSearchModal } from '../stores/search';
-
 import { SearchForm } from './SearchForm';
 import { SearchHelp } from './SearchHelp';
 import { SearchMethodMenuItem } from './SearchMethodMenuItem';

+ 1 - 2
apps/app/src/features/search/client/components/SearchResultMenuItem.tsx

@@ -1,11 +1,10 @@
-import { PagePathLabel, UserPicture } from '@growi/ui/dist/components';
 import React, { type JSX, useCallback } from 'react';
+import { PagePathLabel, UserPicture } from '@growi/ui/dist/components';
 import { useDebounce } from 'usehooks-ts';
 
 import { useSWRxSearch } from '~/stores/search';
 
 import type { GetItemProps } from '../interfaces/downshift';
-
 import { SearchMenuItem } from './SearchMenuItem';
 
 type Props = {

+ 0 - 1
apps/app/src/features/search/client/stores/search.ts

@@ -1,5 +1,4 @@
 import { useCallback } from 'react';
-
 import type { SWRResponse } from 'swr';
 
 import { useStaticSWR } from '~/stores/use-static-swr';

+ 1 - 0
apps/app/src/features/templates/server/routes/apiv3/index.ts

@@ -8,6 +8,7 @@ import {
 } from '@growi/pluginkit/dist/v4/server/index.cjs';
 import express from 'express';
 import { param, query } from 'express-validator';
+
 import { PLUGIN_STORING_PATH } from '~/features/growi-plugin/server/consts';
 import { GrowiPlugin } from '~/features/growi-plugin/server/models';
 import type Crowi from '~/server/crowi';

+ 0 - 1
apps/app/src/interfaces/renderer-options.ts

@@ -1,5 +1,4 @@
 import type { ComponentType } from 'react';
-
 import type {
   Components,
   Options as ReactMarkdownOptions,

+ 1 - 1
apps/app/src/interfaces/ui.ts

@@ -1,5 +1,5 @@
-import type { Nullable } from '@growi/core';
 import type { JSX } from 'react';
+import type { Nullable } from '@growi/core';
 
 import type { IPageForItem } from '~/interfaces/page';
 

+ 1 - 1
apps/app/src/stores-universal/ui.tsx

@@ -2,9 +2,9 @@
  *                          Unions
  *********************************************************** */
 
+import { useCallback } from 'react';
 import type { SWRResponseWithUtils } from '@growi/core/dist/swr';
 import { isServer } from '@growi/core/dist/utils';
-import { useCallback } from 'react';
 import useSWRImmutable from 'swr/immutable';
 
 import { useIsNotFound } from '~/stores/page';

+ 3 - 2
apps/app/src/utils/logger/index.ts

@@ -1,8 +1,9 @@
-import configForDev from '^/config/logger/config.dev';
-import configForProd from '^/config/logger/config.prod';
 import type Logger from 'bunyan';
 import { createLogger, type UniversalBunyanConfig } from 'universal-bunyan';
 
+import configForDev from '^/config/logger/config.dev';
+import configForProd from '^/config/logger/config.prod';
+
 const isProduction = process.env.NODE_ENV === 'production';
 const config = (
   isProduction ? configForProd : configForDev

+ 0 - 1
apps/app/src/utils/page-delete-config.test.ts

@@ -1,5 +1,4 @@
 import { PageDeleteConfigValue } from '../interfaces/page-delete-config';
-
 import { validateDeleteConfigs } from './page-delete-config';
 
 describe('validateDeleteConfigs utility function', () => {

+ 1 - 0
apps/app/test/integration/service/search/search-service.test.js

@@ -3,6 +3,7 @@
  */
 
 import mongoose from 'mongoose';
+
 import NamedQuery from '~/server/models/named-query';
 import SearchService from '~/server/service/search';
 

+ 1 - 0
apps/app/test/integration/service/user-groups.test.ts

@@ -1,6 +1,7 @@
 import type { IGrantedGroup } from '@growi/core';
 import { GroupType, getIdForRef, type IPage, PageGrant } from '@growi/core';
 import mongoose from 'mongoose';
+
 import { PageActionOnGroupDelete } from '../../../src/interfaces/user-group';
 import type Crowi from '../../../src/server/crowi';
 import type { PageDocument, PageModel } from '../../../src/server/models/page';

+ 1 - 0
apps/app/test/integration/service/v5.page.test.ts

@@ -1,6 +1,7 @@
 import type { IPage } from '@growi/core';
 import { addSeconds } from 'date-fns/addSeconds';
 import mongoose from 'mongoose';
+
 import {
   PageActionStage,
   PageActionType,

+ 1 - 0
apps/app/test/integration/service/v5.public-page.test.ts

@@ -2,6 +2,7 @@
 
 import type { IPage, IRevision } from '@growi/core';
 import mongoose from 'mongoose';
+
 import type { CommentModel } from '../../../src/features/comment/server/models/comment';
 import type { IComment } from '../../../src/interfaces/comment';
 import {

+ 1 - 0
apps/pdf-converter/src/controllers/pdf.spec.ts

@@ -1,6 +1,7 @@
 import { PlatformTest } from '@tsed/platform-http/testing';
 import { JobStatus, JobStatusSharedWithGrowi } from 'src/service/pdf-convert';
 import SuperTest from 'supertest';
+
 import Server from '../server';
 
 describe('PdfCtrl', () => {

+ 1 - 0
apps/pdf-converter/src/controllers/pdf.ts

@@ -10,6 +10,7 @@ import {
   Required,
   Returns,
 } from '@tsed/schema';
+
 import PdfConvertService, {
   JobStatus,
   JobStatusSharedWithGrowi,

+ 0 - 1
apps/pdf-converter/src/service/pdf-convert.ts

@@ -2,7 +2,6 @@ import fs from 'node:fs';
 import path from 'node:path';
 import { Readable, Writable } from 'node:stream';
 import { pipeline as pipelinePromise } from 'node:stream/promises';
-
 import { OnInit } from '@tsed/common';
 import { Service } from '@tsed/di';
 import { Logger } from '@tsed/logger';

+ 0 - 1
apps/slackbot-proxy/src/controllers/slack.ts

@@ -1,5 +1,4 @@
 import { ServerResponse } from 'node:http';
-
 import {
   type GrowiCommand,
   type IChannelOptionalId,

+ 18 - 2
biome.json

@@ -25,7 +25,6 @@
       "!apps/app/src/styles/prebuilt/**",
       "!apps/app/tmp/**",
       "!apps/slackbot-proxy/src/public/bootstrap/**",
-      "!packages/editor/**",
       "!packages/pdf-converter-client/src/index.ts",
       "!packages/pdf-converter-client/specs/**",
       "!apps/app/playwright/**",
@@ -48,7 +47,24 @@
   "assist": {
     "actions": {
       "source": {
-        "organizeImports": "on"
+        "organizeImports": {
+          "level": "on",
+          "options": {
+            "groups": [
+              ["react", "react/**"],
+              ["next", "next/**"],
+              [":NODE:", ":PACKAGE:"],
+              ":BLANK_LINE:",
+              ["@/**", "^/**"],
+              ":BLANK_LINE:",
+              "~/**",
+              ":BLANK_LINE:",
+              [":PATH:", "!**/*.css", "!**/*.scss"],
+              ":BLANK_LINE:",
+              ["**/*.css", "**/*.scss"]
+            ]
+          }
+        }
       }
     }
   },

+ 1 - 0
package.json

@@ -56,6 +56,7 @@
     "@types/css-modules": "^1.0.2",
     "@types/eslint": "^8.37.0",
     "@types/estree": "^1.0.1",
+    "@types/glob": "^8.1.0",
     "@types/node": "^20.18.3",
     "@types/path-browserify": "^1.0.0",
     "@typescript-eslint/eslint-plugin": "^5.59.7",

+ 0 - 1
packages/core/src/models/serializers/attachment-serializer.ts

@@ -3,7 +3,6 @@ import { Document } from 'mongoose';
 import type { IAttachment, IUser } from '~/interfaces';
 
 import { isPopulated, isRef, type Ref } from '../../interfaces/common';
-
 import {
   type IUserSerializedSecurely,
   serializeUserSecurely,

+ 1 - 1
packages/core/src/utils/page-path-utils/index.ts

@@ -2,10 +2,10 @@ import escapeStringRegexp from 'escape-string-regexp';
 
 import { isValidObjectId } from '../objectid-utils';
 import { addTrailingSlash } from '../path-utils';
-
 import { isTopPage as _isTopPage } from './is-top-page';
 
 export const isTopPage = _isTopPage;
+
 export * from './generate-children-regexp';
 
 /**

+ 0 - 1
packages/core/src/utils/page-utils.ts

@@ -1,5 +1,4 @@
 import type { IPage } from '..';
-
 import { isTopPage } from './page-path-utils/is-top-page';
 
 // const GRANT_PUBLIC = 1;

+ 0 - 1
packages/core/vite.config.ts

@@ -1,5 +1,4 @@
 import path from 'node:path';
-
 import glob from 'glob';
 import { nodeExternals } from 'rollup-plugin-node-externals';
 import { defineConfig } from 'vite';

+ 1 - 2
packages/editor/.eslintignore

@@ -1,2 +1 @@
-/dist/**
-vite-env.d.ts
+*

+ 0 - 13
packages/editor/.eslintrc.cjs

@@ -1,13 +0,0 @@
-module.exports = {
-  env: { browser: true, es2020: true },
-  extends: [
-    'weseek/react',
-  ],
-  plugins: ['react-refresh'],
-  rules: {
-    'react-refresh/only-export-components': [
-      'warn',
-      { allowConstantExport: true },
-    ],
-  },
-};

+ 1 - 1
packages/editor/package.json

@@ -13,7 +13,7 @@
     "dev": "vite build --mode dev",
     "watch": "pnpm run dev -w --emptyOutDir=false",
     "serve": "vite",
-    "lint:js": "eslint **/*.{js,ts}",
+    "lint:js": "biome check",
     "lint:typecheck": "vue-tsc --noEmit",
     "lint": "npm-run-all -p lint:*"
   },

+ 59 - 45
packages/editor/src/client/components-internal/CodeMirrorEditor/CodeMirrorEditor.tsx

@@ -1,64 +1,68 @@
 import type { DetailedHTMLProps, JSX } from 'react';
-import {
-  forwardRef, useMemo, useRef, useEffect,
-} from 'react';
-
+import { forwardRef, useEffect, useMemo, useRef } from 'react';
 import { indentUnit } from '@codemirror/language';
-import {
-  EditorView,
-} from '@codemirror/view';
+import { EditorView } from '@codemirror/view';
 import { AcceptedUploadFileType } from '@growi/core';
 import type { ReactCodeMirrorProps } from '@uiw/react-codemirror';
 
-import { PasteMode, type EditorSettings, type GlobalCodeMirrorEditorKey } from '../../../consts';
 import {
-  useFileDropzone, FileDropzoneOverlay, useShowTableIcon, getStrFromBol, adjustPasteData,
+  type EditorSettings,
+  type GlobalCodeMirrorEditorKey,
+  PasteMode,
+} from '../../../consts';
+import {
+  adjustPasteData,
+  FileDropzoneOverlay,
+  getStrFromBol,
+  useFileDropzone,
+  useShowTableIcon,
 } from '../../services-internal';
 import { useCodeMirrorEditorIsolated } from '../../stores/codemirror-editor';
 import { useDefaultExtensions } from '../../stores/use-default-extensions';
 import { useEditorSettings } from '../../stores/use-editor-settings';
-
 import { Toolbar } from './Toolbar';
 
-
 import style from './CodeMirrorEditor.module.scss';
 
 const moduleClass = style['codemirror-editor'];
 
-
 // Fix IME cursor position issue by EditContext
 // ref: https://github.com/growilabs/growi/pull/9267
 // ref: https://discuss.codemirror.net/t/issue-with-google-japanese-ime-cursor-position-in-v6/8810/3
 (EditorView as unknown as { EDIT_CONTEXT: boolean }).EDIT_CONTEXT = false;
 
-
-const CodeMirrorEditorContainer = forwardRef<HTMLDivElement, DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>>(
-  (props, ref) => {
-    const { className = '', ...rest } = props;
-    return (
-      <div className={`${className} flex-expand-vert ${style['codemirror-editor-container']}`} ref={ref} {...rest} />
-    );
-  },
-);
+const CodeMirrorEditorContainer = forwardRef<
+  HTMLDivElement,
+  DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
+>((props, ref) => {
+  const { className = '', ...rest } = props;
+  return (
+    <div
+      className={`${className} flex-expand-vert ${style['codemirror-editor-container']}`}
+      ref={ref}
+      {...rest}
+    />
+  );
+});
 
 export type CodeMirrorEditorProps = {
   /**
    * Specity the props for the react-codemirror component. **This must be a memolized object.**
    */
-  cmProps?: ReactCodeMirrorProps,
-  acceptedUploadFileType?: AcceptedUploadFileType,
-  indentSize?: number,
-  editorSettings?: EditorSettings,
-  onSave?: () => void,
-  onUpload?: (files: File[]) => void,
-  onScroll?: () => void,
-}
+  cmProps?: ReactCodeMirrorProps;
+  acceptedUploadFileType?: AcceptedUploadFileType;
+  indentSize?: number;
+  editorSettings?: EditorSettings;
+  onSave?: () => void;
+  onUpload?: (files: File[]) => void;
+  onScroll?: () => void;
+};
 
 type Props = CodeMirrorEditorProps & {
-  editorKey: string | GlobalCodeMirrorEditorKey,
-  className?: string,
-  hideToolbar?: boolean,
-}
+  editorKey: string | GlobalCodeMirrorEditorKey;
+  className?: string;
+  hideToolbar?: boolean;
+};
 
 export const CodeMirrorEditor = (props: Props): JSX.Element => {
   const {
@@ -77,7 +81,11 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
 
   const containerRef = useRef(null);
 
-  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(editorKey, containerRef.current, cmProps);
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(
+    editorKey,
+    containerRef.current,
+    cmProps,
+  );
 
   useDefaultExtensions(codeMirrorEditor);
   useEditorSettings(codeMirrorEditor, editorSettings, onSave);
@@ -92,7 +100,6 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
 
     const cleanupFunction = codeMirrorEditor?.appendExtensions?.(extension);
     return cleanupFunction;
-
   }, [codeMirrorEditor, indentSize]);
 
   const pasteMode = editorSettings?.pasteMode;
@@ -109,7 +116,11 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
       if (event.clipboardData.types.includes('text/plain')) {
         if (codeMirrorEditor == null) return;
 
-        if (pasteMode == null || pasteMode === PasteMode.both || pasteMode === PasteMode.text) {
+        if (
+          pasteMode == null ||
+          pasteMode === PasteMode.both ||
+          pasteMode === PasteMode.text
+        ) {
           const textData = event.clipboardData.getData('text/plain');
 
           const strFromBol = getStrFromBol(editor);
@@ -122,7 +133,11 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
       if (event.clipboardData.types.includes('Files')) {
         if (onUpload == null) return;
 
-        if (pasteMode == null || pasteMode === PasteMode.both || pasteMode === PasteMode.file) {
+        if (
+          pasteMode == null ||
+          pasteMode === PasteMode.both ||
+          pasteMode === PasteMode.file
+        ) {
           onUpload(Array.from(event.clipboardData.files));
         }
       }
@@ -134,11 +149,9 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
 
     const cleanupFunction = codeMirrorEditor?.appendExtensions(extension);
     return cleanupFunction;
-
   }, [codeMirrorEditor, pasteMode, onUpload]);
 
   useEffect(() => {
-
     const handleDrop = (event: DragEvent) => {
       // prevents conflicts between codemirror and react-dropzone during file drops.
       event.preventDefault();
@@ -150,11 +163,9 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
 
     const cleanupFunction = codeMirrorEditor?.appendExtensions(extension);
     return cleanupFunction;
-
   }, [codeMirrorEditor]);
 
   useEffect(() => {
-
     const handleScroll = (event: Event) => {
       event.preventDefault();
       if (onScroll != null) {
@@ -168,7 +179,6 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
 
     const cleanupFunction = codeMirrorEditor?.appendExtensions(extension);
     return cleanupFunction;
-
   }, [onScroll, codeMirrorEditor]);
 
   const {
@@ -189,7 +199,6 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
   });
 
   const fileUploadState = useMemo(() => {
-
     if (isUploading) {
       return 'dropzone-uploading';
     }
@@ -221,8 +230,13 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
   }, [isUploading, isDragAccept, isDragReject, acceptedUploadFileType]);
 
   return (
-    <div className={`${className} ${moduleClass} flex-expand-vert overflow-y-hidden`}>
-      <div {...getRootProps()} className={`dropzone  ${fileUploadState} flex-expand-vert`}>
+    <div
+      className={`${className} ${moduleClass} flex-expand-vert overflow-y-hidden`}
+    >
+      <div
+        {...getRootProps()}
+        className={`dropzone  ${fileUploadState} flex-expand-vert`}
+      >
         <input {...getInputProps()} />
         <FileDropzoneOverlay isEnabled={isDragActive} />
         <CodeMirrorEditorContainer ref={containerRef} />

+ 18 - 24
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/AttachmentsDropdownItem.tsx

@@ -1,36 +1,26 @@
-import type { ReactNode, JSX } from 'react';
-
+import type { JSX, ReactNode } from 'react';
 import type { AcceptedUploadFileType } from '@growi/core';
-import {
-  DropdownItem,
-} from 'reactstrap';
+import { DropdownItem } from 'reactstrap';
 
 import { useFileDropzone } from '../../../services-internal';
 
 type Props = {
-  acceptedUploadFileType: AcceptedUploadFileType,
-  children?: ReactNode,
-  onUpload?: (files: File[]) => void,
-  onClose?: () => void,
-}
+  acceptedUploadFileType: AcceptedUploadFileType;
+  children?: ReactNode;
+  onUpload?: (files: File[]) => void;
+  onClose?: () => void;
+};
 
 export const AttachmentsDropdownItem = (props: Props): JSX.Element => {
+  const { acceptedUploadFileType, children, onUpload, onClose } = props;
 
-  const {
-    acceptedUploadFileType,
-    children,
-    onUpload,
-    onClose,
-  } = props;
-
-  const {
-    getRootProps,
-    getInputProps,
-    open,
-  } = useFileDropzone({
+  const { getRootProps, getInputProps, open } = useFileDropzone({
     // close after uploading
     // https://github.com/growilabs/growi/pull/8564
-    onUpload: (files: File[]) => { onUpload?.(files); onClose?.() },
+    onUpload: (files: File[]) => {
+      onUpload?.(files);
+      onClose?.();
+    },
     acceptedUploadFileType,
     dropzoneOpts: {
       noClick: true,
@@ -45,7 +35,11 @@ export const AttachmentsDropdownItem = (props: Props): JSX.Element => {
   return (
     <div {...getRootProps()} className="dropzone">
       <input {...getInputProps()} />
-      <DropdownItem toggle={false} className="d-flex gap-2 align-items-center" onClick={open}>
+      <DropdownItem
+        toggle={false}
+        className="d-flex gap-2 align-items-center"
+        onClick={open}
+      >
         {children}
       </DropdownItem>
     </div>

+ 35 - 20
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/AttachmentsDropup.tsx

@@ -1,15 +1,13 @@
-import { useState, type JSX } from 'react';
-
+import { type JSX, useState } from 'react';
 import { AcceptedUploadFileType } from '@growi/core';
 import {
-  DropdownToggle,
-  DropdownMenu,
-  DropdownItem,
   Dropdown,
+  DropdownItem,
+  DropdownMenu,
+  DropdownToggle,
 } from 'reactstrap';
 
 import type { GlobalCodeMirrorEditorKey } from '../../../../consts';
-
 import { AttachmentsDropdownItem } from './AttachmentsDropdownItem';
 import { LinkEditButton } from './LinkEditButton';
 
@@ -17,12 +15,11 @@ import styles from './AttachmentsDropup.module.scss';
 
 const btnAttachmentToggleClass = styles['btn-attachment-toggle'];
 
-
 type Props = {
-  editorKey: string | GlobalCodeMirrorEditorKey,
-  acceptedUploadFileType: AcceptedUploadFileType,
-  onUpload?: (files: File[]) => void,
-}
+  editorKey: string | GlobalCodeMirrorEditorKey;
+  acceptedUploadFileType: AcceptedUploadFileType;
+  onUpload?: (files: File[]) => void;
+};
 
 export const AttachmentsDropup = (props: Props): JSX.Element => {
   const { acceptedUploadFileType, editorKey, onUpload } = props;
@@ -31,8 +28,16 @@ export const AttachmentsDropup = (props: Props): JSX.Element => {
 
   return (
     <>
-      <Dropdown isOpen={isOpen} toggle={() => setOpen(!isOpen)} direction="up" className="lh-1">
-        <DropdownToggle className={`${btnAttachmentToggleClass} btn-toolbar-button rounded-circle`} color="unset">
+      <Dropdown
+        isOpen={isOpen}
+        toggle={() => setOpen(!isOpen)}
+        direction="up"
+        className="lh-1"
+      >
+        <DropdownToggle
+          className={`${btnAttachmentToggleClass} btn-toolbar-button rounded-circle`}
+          color="unset"
+        >
           <span className="material-symbols-outlined fs-6">add</span>
         </DropdownToggle>
         <DropdownMenu>
@@ -42,19 +47,29 @@ export const AttachmentsDropup = (props: Props): JSX.Element => {
 
           <DropdownItem divider />
 
-          { acceptedUploadFileType === AcceptedUploadFileType.ALL && (
-            <AttachmentsDropdownItem acceptedUploadFileType={AcceptedUploadFileType.ALL} onUpload={onUpload} onClose={() => setOpen(false)}>
-              <span className="material-symbols-outlined fs-5">attach_file</span>
+          {acceptedUploadFileType === AcceptedUploadFileType.ALL && (
+            <AttachmentsDropdownItem
+              acceptedUploadFileType={AcceptedUploadFileType.ALL}
+              onUpload={onUpload}
+              onClose={() => setOpen(false)}
+            >
+              <span className="material-symbols-outlined fs-5">
+                attach_file
+              </span>
               Files
             </AttachmentsDropdownItem>
-          ) }
+          )}
 
-          { acceptedUploadFileType !== AcceptedUploadFileType.NONE && (
-            <AttachmentsDropdownItem acceptedUploadFileType={AcceptedUploadFileType.IMAGE} onUpload={onUpload} onClose={() => setOpen(false)}>
+          {acceptedUploadFileType !== AcceptedUploadFileType.NONE && (
+            <AttachmentsDropdownItem
+              acceptedUploadFileType={AcceptedUploadFileType.IMAGE}
+              onUpload={onUpload}
+              onClose={() => setOpen(false)}
+            >
               <span className="material-symbols-outlined fs-5">image</span>
               Images
             </AttachmentsDropdownItem>
-          ) }
+          )}
 
           <LinkEditButton editorKey={editorKey} />
         </DropdownMenu>

+ 8 - 4
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/DiagramButton.tsx

@@ -1,10 +1,10 @@
-import { useCallback, type JSX } from 'react';
+import { type JSX, useCallback } from 'react';
 
 import { useDrawioModalForEditor } from '../../../stores/use-drawio';
 
 type Props = {
-  editorKey: string,
-}
+  editorKey: string;
+};
 
 export const DiagramButton = (props: Props): JSX.Element => {
   const { editorKey } = props;
@@ -13,7 +13,11 @@ export const DiagramButton = (props: Props): JSX.Element => {
     openDrawioModal(editorKey);
   }, [editorKey, openDrawioModal]);
   return (
-    <button type="button" className="btn btn-toolbar-button" onClick={onClickDiagramButton}>
+    <button
+      type="button"
+      className="btn btn-toolbar-button"
+      onClick={onClickDiagramButton}
+    >
       {/* TODO: chack and fix font-size. see: https://redmine.weseek.co.jp/issues/143015 */}
       <span className="growi-custom-icons fs-6">drawer_io</span>
     </button>

+ 20 - 20
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/EmojiButton.tsx

@@ -1,8 +1,4 @@
-import {
-  useState, useCallback,
-  type CSSProperties, type JSX,
-} from 'react';
-
+import { type CSSProperties, type JSX, useCallback, useState } from 'react';
 import emojiData from '@emoji-mart/data';
 import Picker from '@emoji-mart/react';
 import { Modal } from 'reactstrap';
@@ -11,8 +7,8 @@ import { useCodeMirrorEditorIsolated } from '../../../stores/codemirror-editor';
 import { useResolvedThemeForEditor } from '../../../stores/use-resolved-theme';
 
 type Props = {
-  editorKey: string,
-}
+  editorKey: string;
+};
 
 export const EmojiButton = (props: Props): JSX.Element => {
   const { editorKey } = props;
@@ -23,20 +19,20 @@ export const EmojiButton = (props: Props): JSX.Element => {
   const { data: resolvedTheme } = useResolvedThemeForEditor();
   const toggle = useCallback(() => setIsOpen(!isOpen), [isOpen]);
 
-  const selectEmoji = useCallback((emoji: { shortcodes: string }): void => {
-
-    if (!isOpen) {
-      return;
-    }
+  const selectEmoji = useCallback(
+    (emoji: { shortcodes: string }): void => {
+      if (!isOpen) {
+        return;
+      }
 
-    codeMirrorEditor?.insertText(emoji.shortcodes);
-
-    toggle();
-  }, [isOpen, toggle, codeMirrorEditor]);
+      codeMirrorEditor?.insertText(emoji.shortcodes);
 
+      toggle();
+    },
+    [isOpen, toggle, codeMirrorEditor],
+  );
 
   const setStyle = useCallback((): CSSProperties => {
-
     const view = codeMirrorEditor?.view;
     const cursorIndex = view?.state.selection.main.head;
 
@@ -73,10 +69,14 @@ export const EmojiButton = (props: Props): JSX.Element => {
       <button type="button" className="btn btn-toolbar-button" onClick={toggle}>
         <span className="material-symbols-outlined fs-5">emoji_emotions</span>
       </button>
-      { isOpen
-      && (
+      {isOpen && (
         <div className="mb-2 d-none d-md-block">
-          <Modal isOpen={isOpen} toggle={toggle} backdropClassName="emoji-picker-modal" fade={false}>
+          <Modal
+            isOpen={isOpen}
+            toggle={toggle}
+            backdropClassName="emoji-picker-modal"
+            fade={false}
+          >
             <span style={setStyle()}>
               <Picker
                 onEmojiSelect={selectEmoji}

+ 11 - 7
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/LinkEditButton.tsx

@@ -1,16 +1,17 @@
-import { useCallback, type JSX } from 'react';
-
+import { type JSX, useCallback } from 'react';
 import { DropdownItem } from 'reactstrap';
 
 import type { GlobalCodeMirrorEditorKey } from '../../../../consts';
-import { getMarkdownLink, replaceFocusedMarkdownLinkWithEditor } from '../../../services-internal';
+import {
+  getMarkdownLink,
+  replaceFocusedMarkdownLinkWithEditor,
+} from '../../../services-internal';
 import { useCodeMirrorEditorIsolated } from '../../../stores/codemirror-editor';
 import { useLinkEditModal } from '../../../stores/use-link-edit-modal';
 
-
 type Props = {
-  editorKey: string | GlobalCodeMirrorEditorKey,
-}
+  editorKey: string | GlobalCodeMirrorEditorKey;
+};
 
 export const LinkEditButton = (props: Props): JSX.Element => {
   const { editorKey } = props;
@@ -33,7 +34,10 @@ export const LinkEditButton = (props: Props): JSX.Element => {
   }, [codeMirrorEditor?.view, openLinkEditModal]);
 
   return (
-    <DropdownItem className="d-flex gap-2 align-items-center" onClick={onClickOpenLinkEditModal}>
+    <DropdownItem
+      className="d-flex gap-2 align-items-center"
+      onClick={onClickOpenLinkEditModal}
+    >
       <span className="material-symbols-outlined fs-5">link</span>Link
     </DropdownItem>
   );

+ 8 - 5
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/TableButton.tsx

@@ -1,12 +1,11 @@
-import { useCallback, type JSX } from 'react';
+import { type JSX, useCallback } from 'react';
 
 import { useCodeMirrorEditorIsolated } from '../../../stores/codemirror-editor';
 import { useHandsontableModalForEditor } from '../../../stores/use-handsontable';
 
-
 type Props = {
-  editorKey: string,
-}
+  editorKey: string;
+};
 
 export const TableButton = (props: Props): JSX.Element => {
   const { editorKey } = props;
@@ -18,7 +17,11 @@ export const TableButton = (props: Props): JSX.Element => {
   }, [editor, openTableModal]);
 
   return (
-    <button type="button" className="btn btn-toolbar-button" onClick={onClickTableButton}>
+    <button
+      type="button"
+      className="btn btn-toolbar-button"
+      onClick={onClickTableButton}
+    >
       <span className="material-symbols-outlined fs-5">table_chart</span>
     </button>
   );

+ 11 - 5
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/TemplateButton.tsx

@@ -1,11 +1,11 @@
-import { useCallback, type JSX } from 'react';
+import { type JSX, useCallback } from 'react';
 
 import { useCodeMirrorEditorIsolated } from '../../../stores/codemirror-editor';
 import { useTemplateModal } from '../../../stores/use-template-modal';
 
 type Props = {
-  editorKey: string,
-}
+  editorKey: string;
+};
 
 export const TemplateButton = (props: Props): JSX.Element => {
   const { editorKey } = props;
@@ -15,14 +15,20 @@ export const TemplateButton = (props: Props): JSX.Element => {
   const onClickTempleteButton = useCallback(() => {
     const editor = codeMirrorEditor?.view;
     if (editor != null) {
-      const insertText = (text: string) => editor.dispatch(editor.state.replaceSelection(text));
+      const insertText = (text: string) =>
+        editor.dispatch(editor.state.replaceSelection(text));
       const onSubmit = (templateText: string) => insertText(templateText);
       openTemplateModal({ onSubmit });
     }
   }, [codeMirrorEditor?.view, openTemplateModal]);
 
   return (
-    <button type="button" className="btn btn-toolbar-button" onClick={onClickTempleteButton} data-testid="open-template-button">
+    <button
+      type="button"
+      className="btn btn-toolbar-button"
+      onClick={onClickTempleteButton}
+      data-testid="open-template-button"
+    >
       <span className="material-symbols-outlined fs-5">file_copy</span>
     </button>
   );

+ 75 - 25
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/TextFormatTools.tsx

@@ -1,5 +1,4 @@
-import { useCallback, useState, type JSX } from 'react';
-
+import { type JSX, useCallback, useState } from 'react';
 import { Collapse } from 'reactstrap';
 
 import type { GlobalCodeMirrorEditorKey } from '../../../../consts';
@@ -10,12 +9,11 @@ import styles from './TextFormatTools.module.scss';
 const btnTextFormatToolsTogglerClass = styles['btn-text-format-tools-toggler'];
 
 type TogglarProps = {
-  isOpen: boolean,
-  onClick?: () => void,
-}
+  isOpen: boolean;
+  onClick?: () => void;
+};
 
 const TextFormatToolsToggler = (props: TogglarProps): JSX.Element => {
-
   const { isOpen, onClick } = props;
 
   const activeClass = isOpen ? 'active' : '';
@@ -32,9 +30,9 @@ const TextFormatToolsToggler = (props: TogglarProps): JSX.Element => {
 };
 
 type TextFormatToolsType = {
-  editorKey: string | GlobalCodeMirrorEditorKey,
-  onTextFormatToolsCollapseChange: () => void,
-}
+  editorKey: string | GlobalCodeMirrorEditorKey;
+  onTextFormatToolsCollapseChange: () => void;
+};
 
 export const TextFormatTools = (props: TextFormatToolsType): JSX.Element => {
   const { editorKey, onTextFormatToolsCollapseChange } = props;
@@ -42,14 +40,17 @@ export const TextFormatTools = (props: TextFormatToolsType): JSX.Element => {
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(editorKey);
 
   const toggle = useCallback(() => {
-    setOpen(bool => !bool);
+    setOpen((bool) => !bool);
   }, []);
 
   const onClickInsertMarkdownElements = (prefix: string, suffix: string) => {
     codeMirrorEditor?.insertMarkdownElements(prefix, suffix);
   };
 
-  const onClickInsertPrefix = (prefix: string, noSpaceIfPrefixExists?: boolean) => {
+  const onClickInsertPrefix = (
+    prefix: string,
+    noSpaceIfPrefixExists?: boolean,
+  ) => {
     codeMirrorEditor?.insertPrefix(prefix, noSpaceIfPrefixExists);
   };
 
@@ -57,35 +58,84 @@ export const TextFormatTools = (props: TextFormatToolsType): JSX.Element => {
     <div className="d-flex">
       <TextFormatToolsToggler isOpen={isOpen} onClick={toggle} />
 
-      <Collapse isOpen={isOpen} horizontal onEntered={onTextFormatToolsCollapseChange} onExited={onTextFormatToolsCollapseChange}>
+      <Collapse
+        isOpen={isOpen}
+        horizontal
+        onEntered={onTextFormatToolsCollapseChange}
+        onExited={onTextFormatToolsCollapseChange}
+      >
         <div className="d-flex px-1 gap-1" style={{ width: '220px' }}>
-          <button type="button" className="btn btn-toolbar-button" onClick={() => onClickInsertMarkdownElements('**', '**')}>
+          <button
+            type="button"
+            className="btn btn-toolbar-button"
+            onClick={() => onClickInsertMarkdownElements('**', '**')}
+          >
             <span className="material-symbols-outlined fs-5">format_bold</span>
           </button>
-          <button type="button" className="btn btn-toolbar-button" onClick={() => onClickInsertMarkdownElements('*', '*')}>
-            <span className="material-symbols-outlined fs-5">format_italic</span>
+          <button
+            type="button"
+            className="btn btn-toolbar-button"
+            onClick={() => onClickInsertMarkdownElements('*', '*')}
+          >
+            <span className="material-symbols-outlined fs-5">
+              format_italic
+            </span>
           </button>
-          <button type="button" className="btn btn-toolbar-button" onClick={() => onClickInsertMarkdownElements('~', '~')}>
-            <span className="material-symbols-outlined fs-5">format_strikethrough</span>
+          <button
+            type="button"
+            className="btn btn-toolbar-button"
+            onClick={() => onClickInsertMarkdownElements('~', '~')}
+          >
+            <span className="material-symbols-outlined fs-5">
+              format_strikethrough
+            </span>
           </button>
-          <button type="button" className="btn btn-toolbar-button" onClick={() => onClickInsertPrefix('#', true)}>
+          <button
+            type="button"
+            className="btn btn-toolbar-button"
+            onClick={() => onClickInsertPrefix('#', true)}
+          >
             {/* TODO: chack and fix font-size. see: https://redmine.weseek.co.jp/issues/143015 */}
             <span className="growi-custom-icons">header</span>
           </button>
-          <button type="button" className="btn btn-toolbar-button" onClick={() => onClickInsertMarkdownElements('`', '`')}>
+          <button
+            type="button"
+            className="btn btn-toolbar-button"
+            onClick={() => onClickInsertMarkdownElements('`', '`')}
+          >
             <span className="material-symbols-outlined fs-5">code</span>
           </button>
-          <button type="button" className="btn btn-toolbar-button" onClick={() => onClickInsertPrefix('-')}>
-            <span className="material-symbols-outlined fs-5">format_list_bulleted</span>
+          <button
+            type="button"
+            className="btn btn-toolbar-button"
+            onClick={() => onClickInsertPrefix('-')}
+          >
+            <span className="material-symbols-outlined fs-5">
+              format_list_bulleted
+            </span>
           </button>
-          <button type="button" className="btn btn-toolbar-button" onClick={() => onClickInsertPrefix('1.')}>
-            <span className="material-symbols-outlined fs-5">format_list_numbered</span>
+          <button
+            type="button"
+            className="btn btn-toolbar-button"
+            onClick={() => onClickInsertPrefix('1.')}
+          >
+            <span className="material-symbols-outlined fs-5">
+              format_list_numbered
+            </span>
           </button>
-          <button type="button" className="btn btn-toolbar-button" onClick={() => onClickInsertPrefix('>')}>
+          <button
+            type="button"
+            className="btn btn-toolbar-button"
+            onClick={() => onClickInsertPrefix('>')}
+          >
             {/* TODO: chack and fix font-size. see: https://redmine.weseek.co.jp/issues/143015 */}
             <span className="growi-custom-icons">format_quote</span>
           </button>
-          <button type="button" className="btn btn-toolbar-button" onClick={() => onClickInsertPrefix('- [ ]')}>
+          <button
+            type="button"
+            className="btn btn-toolbar-button"
+            onClick={() => onClickInsertPrefix('- [ ]')}
+          >
             <span className="material-symbols-outlined fs-5">checklist</span>
           </button>
         </div>

+ 25 - 14
packages/editor/src/client/components-internal/CodeMirrorEditor/Toolbar/Toolbar.tsx

@@ -1,12 +1,8 @@
-import {
-  memo, useCallback, useRef, type JSX,
-} from 'react';
-
+import { type JSX, memo, useCallback, useRef } from 'react';
 import type { AcceptedUploadFileType } from '@growi/core';
 import SimpleBar from 'simplebar-react';
 
 import type { GlobalCodeMirrorEditorKey } from '../../../../consts';
-
 import { AttachmentsDropup } from './AttachmentsDropup';
 import { DiagramButton } from './DiagramButton';
 import { EmojiButton } from './EmojiButton';
@@ -17,10 +13,10 @@ import { TextFormatTools } from './TextFormatTools';
 import styles from './Toolbar.module.scss';
 
 type Props = {
-  editorKey: string | GlobalCodeMirrorEditorKey,
-  acceptedUploadFileType: AcceptedUploadFileType,
-  onUpload?: (files: File[]) => void,
-}
+  editorKey: string | GlobalCodeMirrorEditorKey;
+  acceptedUploadFileType: AcceptedUploadFileType;
+  onUpload?: (files: File[]) => void;
+};
 
 export const Toolbar = memo((props: Props): JSX.Element => {
   const { editorKey, acceptedUploadFileType, onUpload } = props;
@@ -30,16 +26,31 @@ export const Toolbar = memo((props: Props): JSX.Element => {
     if (simpleBarRef.current) {
       simpleBarRef.current.recalculate();
     }
-  }, [simpleBarRef]);
+  }, []);
 
   return (
     <>
-      <div className={`d-flex gap-2 py-1 px-2 px-md-3 border-top ${styles['codemirror-editor-toolbar']} align-items-center`}>
-        <AttachmentsDropup editorKey={editorKey} onUpload={onUpload} acceptedUploadFileType={acceptedUploadFileType} />
+      <div
+        className={`d-flex gap-2 py-1 px-2 px-md-3 border-top ${styles['codemirror-editor-toolbar']} align-items-center`}
+      >
+        <AttachmentsDropup
+          editorKey={editorKey}
+          onUpload={onUpload}
+          acceptedUploadFileType={acceptedUploadFileType}
+        />
         <div className="flex-grow-1">
-          <SimpleBar ref={simpleBarRef} autoHide style={{ overflowY: 'hidden' }}>
+          <SimpleBar
+            ref={simpleBarRef}
+            autoHide
+            style={{ overflowY: 'hidden' }}
+          >
             <div className="d-flex gap-2">
-              <TextFormatTools editorKey={editorKey} onTextFormatToolsCollapseChange={onTextFormatToolsCollapseChange} />
+              <TextFormatTools
+                editorKey={editorKey}
+                onTextFormatToolsCollapseChange={
+                  onTextFormatToolsCollapseChange
+                }
+              />
               <EmojiButton editorKey={editorKey} />
               <TableButton editorKey={editorKey} />
               <DiagramButton editorKey={editorKey} />

+ 46 - 28
packages/editor/src/client/components-internal/playground/Playground.tsx

@@ -1,24 +1,26 @@
-import {
-  useCallback, useEffect, useMemo, useState, type JSX,
-} from 'react';
-
+import { type JSX, useCallback, useEffect, useMemo, useState } from 'react';
 import { AcceptedUploadFileType } from '@growi/core';
-import { GLOBAL_SOCKET_KEY, GLOBAL_SOCKET_NS, useSWRStatic } from '@growi/core/dist/swr';
+import {
+  GLOBAL_SOCKET_KEY,
+  GLOBAL_SOCKET_NS,
+  useSWRStatic,
+} from '@growi/core/dist/swr';
 import type { ReactCodeMirrorProps } from '@uiw/react-codemirror';
 import { toast } from 'react-toastify';
 
-import { GlobalCodeMirrorEditorKey } from '../../../consts';
 import type {
-  EditorSettings, EditorTheme, KeyMapMode, PasteMode,
+  EditorSettings,
+  EditorTheme,
+  KeyMapMode,
+  PasteMode,
 } from '../../../consts';
+import { GlobalCodeMirrorEditorKey } from '../../../consts';
 import { CodeMirrorEditorMain } from '../../components/CodeMirrorEditorMain';
 import { useCodeMirrorEditorIsolated } from '../../stores/codemirror-editor';
-
 import { PlaygroundController } from './PlaygroundController';
 import { Preview } from './Preview';
 
 export const Playground = (): JSX.Element => {
-
   const [markdownToPreview, setMarkdownToPreview] = useState('');
   const [editorTheme, setEditorTheme] = useState<EditorTheme>('defaultlight');
   const [editorKeymap, setEditorKeymap] = useState<KeyMapMode>('default');
@@ -26,7 +28,9 @@ export const Playground = (): JSX.Element => {
   const [enableUnifiedMergeView, setUnifiedMergeViewEnabled] = useState(false);
   const [editorSettings, setEditorSettings] = useState<EditorSettings>();
 
-  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(
+    GlobalCodeMirrorEditorKey.MAIN,
+  );
 
   const { mutate } = useSWRStatic(GLOBAL_SOCKET_KEY);
 
@@ -43,26 +47,29 @@ export const Playground = (): JSX.Element => {
       autoFormatMarkdownTable: true,
       pasteMode: editorPaste,
     });
-  }, [setEditorSettings, editorKeymap, editorTheme, editorPaste]);
+  }, [editorKeymap, editorTheme, editorPaste]);
 
   // initialize global socket
   useEffect(() => {
-    const setUpSocket = async() => {
+    const setUpSocket = async () => {
       const { io } = await import('socket.io-client');
       const socket = io(GLOBAL_SOCKET_NS, {
         transports: ['websocket'],
       });
 
       // eslint-disable-next-line no-console
-      socket.on('error', (err) => { console.error(err) });
+      socket.on('error', (err) => {
+        console.error(err);
+      });
       // eslint-disable-next-line no-console
-      socket.on('connect_error', (err) => { console.error('Failed to connect with websocket.', err) });
+      socket.on('connect_error', (err) => {
+        console.error('Failed to connect with websocket.', err);
+      });
 
       mutate(socket);
     };
 
     setUpSocket();
-
   }, [mutate]);
 
   // set handler to save with shortcut key
@@ -74,22 +81,30 @@ export const Playground = (): JSX.Element => {
 
   // the upload event handler
   // demo of uploading a file.
-  const uploadHandler = useCallback((files: File[]) => {
-    files.forEach((file) => {
-      // set dummy file name.
-      const insertText = `[${file.name}](/attachment/aaaabbbbccccdddd)\n`;
-      codeMirrorEditor?.insertText(insertText);
-    });
-
-  }, [codeMirrorEditor]);
+  const uploadHandler = useCallback(
+    (files: File[]) => {
+      files.forEach((file) => {
+        // set dummy file name.
+        const insertText = `[${file.name}](/attachment/aaaabbbbccccdddd)\n`;
+        codeMirrorEditor?.insertText(insertText);
+      });
+    },
+    [codeMirrorEditor],
+  );
 
-  const cmProps = useMemo<ReactCodeMirrorProps>(() => ({
-    onChange: setMarkdownToPreview,
-  }), []);
+  const cmProps = useMemo<ReactCodeMirrorProps>(
+    () => ({
+      onChange: setMarkdownToPreview,
+    }),
+    [],
+  );
 
   return (
     <div className="d-flex flex-column vw-100 flex-expand-vh-100">
-      <div className="flex-expand-vert justify-content-center align-items-center bg-dark" style={{ minHeight: '83px' }}>
+      <div
+        className="flex-expand-vert justify-content-center align-items-center bg-dark"
+        style={{ minHeight: '83px' }}
+      >
         <div className="text-white">GrowiSubNavigation</div>
       </div>
       <div className="flex-expand-horiz">
@@ -117,7 +132,10 @@ export const Playground = (): JSX.Element => {
           />
         </div>
       </div>
-      <div className="flex-expand-vert justify-content-center align-items-center bg-dark" style={{ minHeight: '50px' }}>
+      <div
+        className="flex-expand-vert justify-content-center align-items-center bg-dark"
+        style={{ minHeight: '50px' }}
+      >
         <div className="text-white">EditorNavbarBottom</div>
       </div>
     </div>

+ 10 - 8
packages/editor/src/client/components-internal/playground/PlaygroundController.tsx

@@ -1,6 +1,4 @@
 import type { EditorTheme, KeyMapMode, PasteMode } from '../../../consts';
-
-
 import { InitEditorValueRow } from './controller/InitEditorValueRow';
 import { KeymapControl } from './controller/KeymapControl';
 import { PasteModeControl } from './controller/PasteModeControl';
@@ -9,18 +7,22 @@ import { ThemeControl } from './controller/ThemeControl';
 import { UnifiedMergeViewControl } from './controller/UnifiedMergeViewControl';
 
 type PlaygroundControllerProps = {
-  setEditorTheme: (value: EditorTheme) => void
-  setEditorKeymap: (value: KeyMapMode) => void
-  setEditorPaste: (value: PasteMode) => void
-  setUnifiedMergeView: (value: boolean) => void
+  setEditorTheme: (value: EditorTheme) => void;
+  setEditorKeymap: (value: KeyMapMode) => void;
+  setEditorPaste: (value: PasteMode) => void;
+  setUnifiedMergeView: (value: boolean) => void;
 };
 
-export const PlaygroundController = (props: PlaygroundControllerProps): JSX.Element => {
+export const PlaygroundController = (
+  props: PlaygroundControllerProps,
+): JSX.Element => {
   return (
     <div className="container">
       <InitEditorValueRow />
       <SetCaretLineRow />
-      <UnifiedMergeViewControl onChange={bool => props.setUnifiedMergeView(bool)} />
+      <UnifiedMergeViewControl
+        onChange={(bool) => props.setUnifiedMergeView(bool)}
+      />
       <ThemeControl setEditorTheme={props.setEditorTheme} />
       <KeymapControl setEditorKeymap={props.setEditorKeymap} />
       <PasteModeControl setEditorPaste={props.setEditorPaste} />

+ 2 - 2
packages/editor/src/client/components-internal/playground/Preview.tsx

@@ -1,8 +1,8 @@
 import type { JSX } from 'react';
 
 type Props = {
-  markdown?: string,
-}
+  markdown?: string;
+};
 
 export const Preview = (props: Props): JSX.Element => {
   return (

+ 7 - 3
packages/editor/src/client/components-internal/playground/controller/KeymapControl.tsx

@@ -1,18 +1,22 @@
 import type { KeyMapMode } from '../../../../consts';
 import { AllKeyMap } from '../../../../consts';
-
 import { OutlineSecondaryButtons } from './OutlineSecondaryButtons';
 
 type KeymapControlProps = {
   setEditorKeymap: (value: KeyMapMode) => void;
 };
 
-export const KeymapControl = ({ setEditorKeymap }: KeymapControlProps): JSX.Element => {
+export const KeymapControl = ({
+  setEditorKeymap,
+}: KeymapControlProps): JSX.Element => {
   return (
     <div className="row mt-5">
       <h2>Keymaps</h2>
       <div className="col">
-        <OutlineSecondaryButtons<KeyMapMode> update={setEditorKeymap} items={AllKeyMap} />
+        <OutlineSecondaryButtons<KeyMapMode>
+          update={setEditorKeymap}
+          items={AllKeyMap}
+        />
       </div>
     </div>
   );

+ 6 - 6
packages/editor/src/client/components-internal/playground/controller/OutlineSecondaryButtons.tsx

@@ -1,15 +1,15 @@
 type OutlineSecondaryButtonsProps<V> = {
-  update: (value: V) => void,
-  items: V[],
-}
+  update: (value: V) => void;
+  items: V[];
+};
 
-export const OutlineSecondaryButtons = <V extends { toString: () => string }, >(
+export const OutlineSecondaryButtons = <V extends { toString: () => string }>(
   props: OutlineSecondaryButtonsProps<V>,
 ): JSX.Element => {
   const { update, items } = props;
   return (
     <div className="d-flex flex-wrap gap-1">
-      { items.map(item => (
+      {items.map((item) => (
         <button
           key={item.toString()}
           type="button"
@@ -18,7 +18,7 @@ export const OutlineSecondaryButtons = <V extends { toString: () => string }, >(
         >
           {item.toString()}
         </button>
-      )) }
+      ))}
     </div>
   );
 };

+ 7 - 3
packages/editor/src/client/components-internal/playground/controller/PasteModeControl.tsx

@@ -1,18 +1,22 @@
 import type { PasteMode } from '../../../../consts';
 import { AllPasteMode } from '../../../../consts';
-
 import { OutlineSecondaryButtons } from './OutlineSecondaryButtons';
 
 type PasteModeControlProps = {
   setEditorPaste: (value: PasteMode) => void;
 };
 
-export const PasteModeControl = ({ setEditorPaste }: PasteModeControlProps): JSX.Element => {
+export const PasteModeControl = ({
+  setEditorPaste,
+}: PasteModeControlProps): JSX.Element => {
   return (
     <div className="row mt-5">
       <h2>Paste mode</h2>
       <div className="col">
-        <OutlineSecondaryButtons<PasteMode> update={setEditorPaste} items={AllPasteMode} />
+        <OutlineSecondaryButtons<PasteMode>
+          update={setEditorPaste}
+          items={AllPasteMode}
+        />
       </div>
     </div>
   );

+ 7 - 1
packages/editor/src/client/components-internal/playground/controller/SetCaretLineRow.tsx

@@ -33,7 +33,13 @@ export const SetCaretLineRow = (): JSX.Element => {
             aria-label="line number"
             aria-describedby="button-set-cursor"
           />
-          <button type="submit" className="btn btn-outline-secondary" id="button-set-cursor">Set the cursor</button>
+          <button
+            type="submit"
+            className="btn btn-outline-secondary"
+            id="button-set-cursor"
+          >
+            Set the cursor
+          </button>
         </div>
       </div>
     </form>

+ 7 - 3
packages/editor/src/client/components-internal/playground/controller/ThemeControl.tsx

@@ -1,18 +1,22 @@
 import type { EditorTheme } from '../../../../consts';
 import { AllEditorTheme } from '../../../../consts';
-
 import { OutlineSecondaryButtons } from './OutlineSecondaryButtons';
 
 type ThemeControlProps = {
   setEditorTheme: (value: EditorTheme) => void;
 };
 
-export const ThemeControl = ({ setEditorTheme }: ThemeControlProps): JSX.Element => {
+export const ThemeControl = ({
+  setEditorTheme,
+}: ThemeControlProps): JSX.Element => {
   return (
     <div className="row mt-5">
       <h2>Themes</h2>
       <div className="col">
-        <OutlineSecondaryButtons<EditorTheme> update={setEditorTheme} items={AllEditorTheme} />
+        <OutlineSecondaryButtons<EditorTheme>
+          update={setEditorTheme}
+          items={AllEditorTheme}
+        />
       </div>
     </div>
   );

+ 17 - 4
packages/editor/src/client/components-internal/playground/controller/UnifiedMergeViewControl.tsx

@@ -2,15 +2,28 @@ type UnifiedMergeViewControlProps = {
   onChange: (value: boolean) => void;
 };
 
-export const UnifiedMergeViewControl = ({ onChange }: UnifiedMergeViewControlProps): JSX.Element => {
+export const UnifiedMergeViewControl = ({
+  onChange,
+}: UnifiedMergeViewControlProps): JSX.Element => {
   return (
     <div className="row mt-5">
       <div className="col">
         <div className="form-check form-switch">
-          <input className="form-check-input" type="checkbox" role="switch" id="flexSwitchCheckUnifiedMergeView" onChange={e => onChange(e.target.checked)} />
-          <label className="form-check-label" htmlFor="flexSwitchCheckUnifiedMergeView">Unified Merge View</label>
+          <input
+            className="form-check-input"
+            type="checkbox"
+            // biome-ignore lint/a11y/useAriaPropsForRole: ignore
+            role="switch"
+            id="flexSwitchCheckUnifiedMergeView"
+            onChange={(e) => onChange(e.target.checked)}
+          />
+          <label
+            className="form-check-label"
+            htmlFor="flexSwitchCheckUnifiedMergeView"
+          >
+            Unified Merge View
+          </label>
         </div>
-
       </div>
     </div>
   );

+ 12 - 20
packages/editor/src/client/components/CodeMirrorEditorComment.tsx

@@ -1,25 +1,22 @@
-import { memo, useEffect, type JSX } from 'react';
-
+import { type JSX, memo, useEffect } from 'react';
 import type { Extension } from '@codemirror/state';
 import { keymap } from '@codemirror/view';
 
 import type { GlobalCodeMirrorEditorKey } from '../../consts';
-import { CodeMirrorEditor, type CodeMirrorEditorProps } from '../components-internal/CodeMirrorEditor';
+import {
+  CodeMirrorEditor,
+  type CodeMirrorEditorProps,
+} from '../components-internal/CodeMirrorEditor';
 import { useCodeMirrorEditorIsolated } from '../stores/codemirror-editor';
 
-
-const additionalExtensions: Extension[] = [
-];
+const additionalExtensions: Extension[] = [];
 
 type Props = CodeMirrorEditorProps & {
-  editorKey: string | GlobalCodeMirrorEditorKey,
-}
+  editorKey: string | GlobalCodeMirrorEditorKey;
+};
 
 export const CodeMirrorEditorComment = memo((props: Props): JSX.Element => {
-  const {
-    editorKey,
-    onSave, ...rest
-  } = props;
+  const { editorKey, onSave, ...rest } = props;
 
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(editorKey);
 
@@ -48,16 +45,11 @@ export const CodeMirrorEditorComment = memo((props: Props): JSX.Element => {
       },
     ]);
 
-    const cleanupFunction = codeMirrorEditor?.appendExtensions?.(keymapExtension);
+    const cleanupFunction =
+      codeMirrorEditor?.appendExtensions?.(keymapExtension);
 
     return cleanupFunction;
   }, [codeMirrorEditor, onSave]);
 
-  return (
-    <CodeMirrorEditor
-      editorKey={editorKey}
-      onSave={onSave}
-      {...rest}
-    />
-  );
+  return <CodeMirrorEditor editorKey={editorKey} onSave={onSave} {...rest} />;
 });

+ 39 - 32
packages/editor/src/client/components/CodeMirrorEditorMain.tsx

@@ -1,6 +1,5 @@
-import { useEffect, useMemo, type JSX } from 'react';
-
-import { type Extension } from '@codemirror/state';
+import { type JSX, useEffect, useMemo } from 'react';
+import type { Extension } from '@codemirror/state';
 import { keymap, scrollPastEnd } from '@codemirror/view';
 import type { IUserHasId } from '@growi/core/dist/interfaces';
 import type { ReactCodeMirrorProps } from '@uiw/react-codemirror';
@@ -8,37 +7,44 @@ import deepmerge from 'ts-deepmerge';
 
 import { GlobalCodeMirrorEditorKey } from '../../consts';
 import type { EditingClient } from '../../interfaces';
-import { CodeMirrorEditor, type CodeMirrorEditorProps } from '../components-internal/CodeMirrorEditor';
-import { setDataLine, useUnifiedMergeView, codemirrorEditorClassForUnifiedMergeView } from '../services-internal';
+import {
+  CodeMirrorEditor,
+  type CodeMirrorEditorProps,
+} from '../components-internal/CodeMirrorEditor';
+import {
+  codemirrorEditorClassForUnifiedMergeView,
+  setDataLine,
+  useUnifiedMergeView,
+} from '../services-internal';
 import { useCodeMirrorEditorIsolated } from '../stores/codemirror-editor';
 import { useCollaborativeEditorMode } from '../stores/use-collaborative-editor-mode';
 
-
-const additionalExtensions: Extension[] = [
-  [
-    scrollPastEnd(),
-    setDataLine,
-  ],
-];
+const additionalExtensions: Extension[] = [[scrollPastEnd(), setDataLine]];
 
 type Props = CodeMirrorEditorProps & {
-  user?: IUserHasId,
-  pageId?: string,
-  initialValue?: string,
-  enableCollaboration?: boolean,
-  enableUnifiedMergeView?: boolean,
-  onEditorsUpdated?: (clientList: EditingClient[]) => void,
-}
+  user?: IUserHasId;
+  pageId?: string;
+  initialValue?: string;
+  enableCollaboration?: boolean;
+  enableUnifiedMergeView?: boolean;
+  onEditorsUpdated?: (clientList: EditingClient[]) => void;
+};
 
 export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
   const {
-    user, pageId,
-    enableCollaboration = false, enableUnifiedMergeView = false,
+    user,
+    pageId,
+    enableCollaboration = false,
+    enableUnifiedMergeView = false,
     cmProps,
-    onSave, onEditorsUpdated, ...otherProps
+    onSave,
+    onEditorsUpdated,
+    ...otherProps
   } = props;
 
-  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(
+    GlobalCodeMirrorEditorKey.MAIN,
+  );
 
   useCollaborativeEditorMode(enableCollaboration, codeMirrorEditor, {
     user,
@@ -79,15 +85,16 @@ export const CodeMirrorEditorMain = (props: Props): JSX.Element => {
     return cleanupFunction;
   }, [codeMirrorEditor, onSave]);
 
-  const cmPropsOverride = useMemo<ReactCodeMirrorProps>(() => deepmerge(
-    cmProps ?? {},
-    {
-      // Disable the basic history configuration since this component uses Y.UndoManager instead
-      basicSetup: {
-        history: false,
-      },
-    },
-  ), [cmProps]);
+  const cmPropsOverride = useMemo<ReactCodeMirrorProps>(
+    () =>
+      deepmerge(cmProps ?? {}, {
+        // Disable the basic history configuration since this component uses Y.UndoManager instead
+        basicSetup: {
+          history: false,
+        },
+      }),
+    [cmProps],
+  );
 
   return (
     <CodeMirrorEditor

+ 16 - 17
packages/editor/src/client/components/CodeMirrorEditorReadOnly.tsx

@@ -1,6 +1,5 @@
-import { useEffect, type JSX } from 'react';
-
-import { type Extension, EditorState, Prec } from '@codemirror/state';
+import { type JSX, useEffect } from 'react';
+import { EditorState, type Extension, Prec } from '@codemirror/state';
 import { EditorView, keymap } from '@codemirror/view';
 
 import { GlobalCodeMirrorEditorKey } from '../../consts';
@@ -8,22 +7,22 @@ import { CodeMirrorEditor } from '../components-internal/CodeMirrorEditor';
 import { setDataLine } from '../services-internal';
 import { useCodeMirrorEditorIsolated } from '../stores/codemirror-editor';
 
-
 const additionalExtensions: Extension[] = [
-  [
-    setDataLine,
-    EditorState.readOnly.of(true),
-    EditorView.editable.of(false),
-  ],
+  [setDataLine, EditorState.readOnly.of(true), EditorView.editable.of(false)],
 ];
 
 type Props = {
-  markdown?: string,
-  onScroll?: () => void,
-}
+  markdown?: string;
+  onScroll?: () => void;
+};
 
-export const CodeMirrorEditorReadOnly = ({ markdown, onScroll }: Props): JSX.Element => {
-  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.READONLY);
+export const CodeMirrorEditorReadOnly = ({
+  markdown,
+  onScroll,
+}: Props): JSX.Element => {
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(
+    GlobalCodeMirrorEditorKey.READONLY,
+  );
 
   codeMirrorEditor?.initDoc(markdown);
 
@@ -31,7 +30,6 @@ export const CodeMirrorEditorReadOnly = ({ markdown, onScroll }: Props): JSX.Ele
     return codeMirrorEditor?.appendExtensions?.(additionalExtensions);
   }, [codeMirrorEditor]);
 
-
   // prevent Ctrl+V and paste
   useEffect(() => {
     const extension = keymap.of([
@@ -57,12 +55,13 @@ export const CodeMirrorEditorReadOnly = ({ markdown, onScroll }: Props): JSX.Ele
       paste: handlePaste,
     });
 
-    const cleanupFunction = codeMirrorEditor?.appendExtensions?.(Prec.high(extension));
+    const cleanupFunction = codeMirrorEditor?.appendExtensions?.(
+      Prec.high(extension),
+    );
 
     return cleanupFunction;
   }, [codeMirrorEditor]);
 
-
   return (
     <CodeMirrorEditor
       hideToolbar

+ 7 - 8
packages/editor/src/client/components/diff/CodeMirrorEditorDiff.tsx

@@ -1,7 +1,4 @@
-import {
-  useEffect, useRef, useMemo, type JSX,
-} from 'react';
-
+import { type JSX, useEffect, useMemo, useRef } from 'react';
 import type { Extension } from '@codemirror/state';
 import { placeholder, scrollPastEnd } from '@codemirror/view';
 import type { ReactCodeMirrorProps } from '@uiw/react-codemirror';
@@ -26,7 +23,11 @@ export const CodeMirrorEditorDiff = (): JSX.Element => {
     return {};
   }, []);
 
-  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.DIFF, codeMirrorRef.current, cmProps);
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(
+    GlobalCodeMirrorEditorKey.DIFF,
+    codeMirrorRef.current,
+    cmProps,
+  );
 
   useDefaultExtensions(codeMirrorEditor);
   useEditorSettings(codeMirrorEditor);
@@ -36,7 +37,5 @@ export const CodeMirrorEditorDiff = (): JSX.Element => {
     return codeMirrorEditor?.appendExtensions?.(additionalExtensions);
   }, [codeMirrorEditor]);
 
-  return (
-    <div ref={codeMirrorRef} />
-  );
+  return <div ref={codeMirrorRef} />;
 };

+ 5 - 6
packages/editor/src/client/components/diff/MergeViewer.tsx

@@ -1,13 +1,12 @@
 import { memo, useEffect, useRef } from 'react';
-
 import { MergeView } from '@codemirror/merge';
-import { type Extension, EditorState } from '@codemirror/state';
-import { EditorView, basicSetup } from 'codemirror';
+import { EditorState, type Extension } from '@codemirror/state';
+import { basicSetup, EditorView } from 'codemirror';
 
 type Props = {
-  leftBody: string
-  rightBody: string
-}
+  leftBody: string;
+  rightBody: string;
+};
 
 const MergeViewerExtensions: Extension = [
   basicSetup,

+ 3 - 1
packages/editor/src/client/services-internal/editor-theme/index.ts

@@ -2,7 +2,9 @@ import type { Extension } from '@codemirror/state';
 
 import type { EditorTheme } from '../../../consts';
 
-export const getEditorTheme = async(themeName?: EditorTheme): Promise<Extension> => {
+export const getEditorTheme = async (
+  themeName?: EditorTheme,
+): Promise<Extension> => {
   switch (themeName) {
     case 'eclipse':
       return (await import('./eclipse')).eclipse;

+ 9 - 1
packages/editor/src/client/services-internal/editor-theme/original-dark.ts

@@ -23,7 +23,15 @@ export const originalDark = createTheme({
     // { tag: t.moduleKeyword, color: 'red' },
     { tag: [t.tagName, t.modifier], color: '#BA6666' },
     { tag: [t.url, t.escape, t.regexp, t.link], color: '#8FA7C7' },
-    { tag: [t.number, t.definition(t.tagName), t.className, t.definition(t.variableName)], color: '#fbac52' },
+    {
+      tag: [
+        t.number,
+        t.definition(t.tagName),
+        t.className,
+        t.definition(t.variableName),
+      ],
+      color: '#fbac52',
+    },
     { tag: [t.atom, t.bool, t.special(t.variableName)], color: '#BA6666' },
     { tag: t.variableName, color: '#539ac4' },
     { tag: [t.propertyName, t.typeName], color: '#629ccd' },

+ 17 - 3
packages/editor/src/client/services-internal/editor-theme/original-light.ts

@@ -4,7 +4,6 @@ import type { Extension } from '@codemirror/state';
 import { tags as t } from '@lezer/highlight';
 import { createTheme } from '@uiw/codemirror-themes';
 
-
 export const originalLight: Extension = createTheme({
   theme: 'light',
   settings: {
@@ -19,7 +18,10 @@ export const originalLight: Extension = createTheme({
     { tag: [t.standard(t.tagName), t.tagName], color: '#377148' },
     { tag: [t.comment, t.bracket], color: '#6a737d' },
     { tag: [t.className, t.propertyName], color: '#6f42c1' },
-    { tag: [t.keyword, t.typeName, t.typeOperator, t.typeName], color: '#d73a49' },
+    {
+      tag: [t.keyword, t.typeName, t.typeOperator, t.typeName],
+      color: '#d73a49',
+    },
     { tag: [t.name, t.quote], color: '#22863a' },
     { tag: [t.heading], color: '#24292e', fontWeight: 'bold' },
     { tag: [t.emphasis], color: '#24292e', fontStyle: 'italic' },
@@ -29,7 +31,19 @@ export const originalLight: Extension = createTheme({
     { tag: [t.url, t.escape, t.regexp, t.link], color: '#032f62' },
     { tag: t.link, textDecoration: 'underline' },
     { tag: t.strikethrough, textDecoration: 'line-through' },
-    { tag: [t.variableName, t.attributeName, t.number, t.operator, t.character, t.brace, t.processingInstruction, t.inserted], color: '#516883' },
+    {
+      tag: [
+        t.variableName,
+        t.attributeName,
+        t.number,
+        t.operator,
+        t.character,
+        t.brace,
+        t.processingInstruction,
+        t.inserted,
+      ],
+      color: '#516883',
+    },
     { tag: [t.strong], color: '#744763' },
     { tag: t.invalid, color: '#cb2431' },
   ],

+ 24 - 17
packages/editor/src/client/services-internal/extensions/emojiAutocompletionSettings.ts

@@ -1,8 +1,11 @@
-import { type CompletionContext, type Completion, autocompletion } from '@codemirror/autocomplete';
+import {
+  autocompletion,
+  type Completion,
+  type CompletionContext,
+} from '@codemirror/autocomplete';
 import { syntaxTree } from '@codemirror/language';
 import emojiData from '@emoji-mart/data';
 
-
 const getEmojiDataArray = (): string[] => {
   const rawEmojiDataArray = emojiData.categories;
 
@@ -20,7 +23,9 @@ const getEmojiDataArray = (): string[] => {
   const fixedEmojiDataArray: string[] = [];
 
   emojiCategoriesData.forEach((value) => {
-    const tempArray = rawEmojiDataArray.find((obj: {id: string}) => obj.id === value)?.emojis;
+    const tempArray = rawEmojiDataArray.find(
+      (obj: { id: string }) => obj.id === value,
+    )?.emojis;
 
     if (tempArray == null) {
       return;
@@ -34,13 +39,13 @@ const getEmojiDataArray = (): string[] => {
 
 const emojiDataArray = getEmojiDataArray();
 
-const emojiOptions = emojiDataArray.map(
-  tag => ({ label: `:${tag}:`, type: tag }),
-);
+const emojiOptions = emojiDataArray.map((tag) => ({
+  label: `:${tag}:`,
+  type: tag,
+}));
 
 const TWO_OR_MORE_WORD_CHARACTERS_REGEX = /:\w{2,}$/;
 
-
 // EmojiAutocompletion is activated when two characters are entered into the editor.
 const emojiAutocompletion = (context: CompletionContext) => {
   const nodeBefore = syntaxTree(context.state).resolveInner(context.pos, -1);
@@ -57,17 +62,19 @@ const emojiAutocompletion = (context: CompletionContext) => {
 };
 
 export const emojiAutocompletionSettings = autocompletion({
-  addToOptions: [{
-    render: (completion: Completion) => {
-      const emojiName = completion.type ?? '';
-      const emoji = emojiData.emojis[emojiName].skins[0].native;
-
-      const element = document.createElement('span');
-      element.innerHTML = emoji;
-      return element;
+  addToOptions: [
+    {
+      render: (completion: Completion) => {
+        const emojiName = completion.type ?? '';
+        const emoji = emojiData.emojis[emojiName].skins[0].native;
+
+        const element = document.createElement('span');
+        element.innerHTML = emoji;
+        return element;
+      },
+      position: 20,
     },
-    position: 20,
-  }],
+  ],
   icons: false,
   override: [emojiAutocompletion],
 });

+ 3 - 7
packages/editor/src/client/services-internal/extensions/setDataLine.ts

@@ -1,15 +1,13 @@
-
 // Ref: https://github.com/uiwjs/react-codemirror/blob/bf3b862923d0cb04ccf4bb9da0791bdc7fd6d29b/extensions/classname/src/index.ts
 
-
 import { RangeSetBuilder } from '@codemirror/state';
-import type { EditorView, DecorationSet, ViewUpdate } from '@codemirror/view';
+import type { DecorationSet, EditorView, ViewUpdate } from '@codemirror/view';
 import { Decoration, ViewPlugin } from '@codemirror/view';
 
 const stripeDeco = (view: EditorView) => {
   const builder = new RangeSetBuilder<Decoration>();
   for (const { from, to } of view.visibleRanges) {
-    for (let pos = from; pos <= to;) {
+    for (let pos = from; pos <= to; ) {
       const line = view.state.doc.lineAt(pos);
       const cls = line.number.toString();
       builder.add(
@@ -27,7 +25,6 @@ const stripeDeco = (view: EditorView) => {
 
 export const setDataLine = ViewPlugin.fromClass(
   class {
-
     decorations: DecorationSet;
 
     constructor(view: EditorView) {
@@ -39,9 +36,8 @@ export const setDataLine = ViewPlugin.fromClass(
         this.decorations = stripeDeco(update.view);
       }
     }
-
   },
   {
-    decorations: v => v.decorations,
+    decorations: (v) => v.decorations,
   },
 );

+ 1 - 1
packages/editor/src/client/services-internal/file-dropzone/index.ts

@@ -1,2 +1,2 @@
-export * from './use-file-dropzone/use-file-dropzone';
 export * from './use-file-dropzone/FileDropzoneOverlay';
+export * from './use-file-dropzone/use-file-dropzone';

+ 3 - 4
packages/editor/src/client/services-internal/file-dropzone/use-file-dropzone/FileDropzoneOverlay.tsx

@@ -1,8 +1,8 @@
 import type { JSX } from 'react';
 
 type Props = {
-  isEnabled: boolean,
-}
+  isEnabled: boolean;
+};
 
 export const FileDropzoneOverlay = (props: Props): JSX.Element => {
   const { isEnabled } = props;
@@ -11,8 +11,7 @@ export const FileDropzoneOverlay = (props: Props): JSX.Element => {
     return (
       <div className="overlay overlay-dropzone-active">
         <span className="overlay-content">
-          <span className="overlay-icon material-symbols-outlined">
-          </span>
+          <span className="overlay-icon material-symbols-outlined"></span>
         </span>
       </div>
     );

+ 27 - 25
packages/editor/src/client/services-internal/file-dropzone/use-file-dropzone/use-file-dropzone.ts

@@ -1,41 +1,43 @@
 import { useCallback, useState } from 'react';
-
 import { AcceptedUploadFileType } from '@growi/core';
+import type { Accept, DropzoneOptions, DropzoneState } from 'react-dropzone';
 import { useDropzone } from 'react-dropzone';
-import type { DropzoneOptions, DropzoneState, Accept } from 'react-dropzone';
-
 
 type FileDropzoneState = DropzoneState & {
-  isUploading: boolean,
-}
+  isUploading: boolean;
+};
 
 type Props = {
-  acceptedUploadFileType: AcceptedUploadFileType,
-  dropzoneOpts?: DropzoneOptions,
-  onUpload?: (files: File[]) => void,
-}
+  acceptedUploadFileType: AcceptedUploadFileType;
+  dropzoneOpts?: DropzoneOptions;
+  onUpload?: (files: File[]) => void;
+};
 
 export const useFileDropzone = (props: Props): FileDropzoneState => {
-
   const { acceptedUploadFileType, dropzoneOpts, onUpload } = props;
 
   const [isUploading, setIsUploading] = useState(false);
 
-  const dropHandler = useCallback((acceptedFiles: File[]) => {
-    if (onUpload == null) {
-      return;
-    }
-    if (acceptedUploadFileType === AcceptedUploadFileType.NONE) {
-      return;
-    }
-
-    setIsUploading(true);
-    onUpload(acceptedFiles);
-    setIsUploading(false);
-
-  }, [onUpload, setIsUploading, acceptedUploadFileType]);
-
-  const accept: Accept | undefined = (acceptedUploadFileType === AcceptedUploadFileType.IMAGE) ? { 'image/*': [] } : undefined;
+  const dropHandler = useCallback(
+    (acceptedFiles: File[]) => {
+      if (onUpload == null) {
+        return;
+      }
+      if (acceptedUploadFileType === AcceptedUploadFileType.NONE) {
+        return;
+      }
+
+      setIsUploading(true);
+      onUpload(acceptedFiles);
+      setIsUploading(false);
+    },
+    [onUpload, acceptedUploadFileType],
+  );
+
+  const accept: Accept | undefined =
+    acceptedUploadFileType === AcceptedUploadFileType.IMAGE
+      ? { 'image/*': [] }
+      : undefined;
 
   const dzState = useDropzone({
     onDrop: dropHandler,

+ 7 - 3
packages/editor/src/client/services-internal/keymaps/index.ts

@@ -3,15 +3,19 @@ import { keymap } from '@codemirror/view';
 
 import type { KeyMapMode } from '../../../consts';
 
-
-export const getKeymap = async(keyMapName?: KeyMapMode, onSave?: () => void): Promise<Extension> => {
+export const getKeymap = async (
+  keyMapName?: KeyMapMode,
+  onSave?: () => void,
+): Promise<Extension> => {
   switch (keyMapName) {
     case 'vim':
       return (await import('./vim')).vimKeymap(onSave);
     case 'emacs':
       return (await import('@replit/codemirror-emacs')).emacs();
     case 'vscode':
-      return keymap.of((await import('@replit/codemirror-vscode-keymap')).vscodeKeymap);
+      return keymap.of(
+        (await import('@replit/codemirror-vscode-keymap')).vscodeKeymap,
+      );
   }
   return keymap.of((await import('@codemirror/commands')).defaultKeymap);
 };

+ 8 - 3
packages/editor/src/client/services-internal/link-util/markdown-link-util.ts

@@ -12,14 +12,16 @@ const doc = (editor: EditorView) => {
 
 const getCursorLine = (editor: EditorView) => {
   return doc(editor).lineAt(curPos(editor));
-
 };
 
 export const isInLink = (editor: EditorView): boolean => {
   const cursorLine = getCursorLine(editor);
   const startPos = curPos(editor) - cursorLine.from;
 
-  const { beginningOfLink, endOfLink } = Linker.getBeginningAndEndIndexOfLink(cursorLine.text, startPos);
+  const { beginningOfLink, endOfLink } = Linker.getBeginningAndEndIndexOfLink(
+    cursorLine.text,
+    startPos,
+  );
   return beginningOfLink >= 0 && endOfLink >= 0;
 };
 export const getMarkdownLink = (editor: EditorView): Linker => {
@@ -36,6 +38,9 @@ export const getMarkdownLink = (editor: EditorView): Linker => {
   return Linker.fromLineWithIndex(cursorLine.text, startPos);
 };
 
-export const replaceFocusedMarkdownLinkWithEditor = (editor: EditorView, linkText: string): void => {
+export const replaceFocusedMarkdownLinkWithEditor = (
+  editor: EditorView,
+  linkText: string,
+): void => {
   editor.dispatch(editor.state.replaceSelection(linkText));
 };

Некоторые файлы не были показаны из-за большого количества измененных файлов