Browse Source

Merge branch 'master' into feat/146155-design-coding-of-search-result-page

Shun Miyazawa 1 year ago
parent
commit
0f8abde26a
98 changed files with 939 additions and 431 deletions
  1. 11 0
      .changeset/config.json
  2. 1 0
      .eslintrc.js
  3. 18 1
      CHANGELOG.md
  4. 0 1
      apps/app/.eslintrc.js
  5. 1 1
      apps/app/docker/README.md
  6. 6 6
      apps/app/package.json
  7. 0 147
      apps/app/src/client/models/MarkdownTable.js
  8. 1 1
      apps/app/src/client/services/side-effects/handsontable-modal-launcher-for-view.ts
  9. 28 0
      apps/app/src/components/Layout/BasicLayout.module.scss
  10. 7 1
      apps/app/src/components/Layout/BasicLayout.tsx
  11. 1 1
      apps/app/src/components/Navbar/GrowiContextualSubNavigation.module.scss
  12. 1 1
      apps/app/src/components/Page/markdown-table-util-for-view.ts
  13. 15 10
      apps/app/src/components/PageControls/PageControls.tsx
  14. 1 1
      apps/app/src/components/PageEditor/EditorNavbarBottom.module.scss
  15. 1 1
      apps/app/src/components/PageEditor/HandsontableModal.tsx
  16. 1 1
      apps/app/src/components/PageEditor/LinkEditModal.tsx
  17. 1 1
      apps/app/src/components/PageEditor/MarkdownTableDataImportForm.tsx
  18. 4 3
      apps/app/src/components/PageEditor/PageEditor.tsx
  19. 1 2
      apps/app/src/components/PageEditor/markdown-table-util-for-editor.ts
  20. 1 1
      apps/app/src/components/Sidebar/SidebarHead/ToggleCollapseButton.module.scss
  21. 3 4
      apps/app/src/server/service/yjs-connection-manager.ts
  22. 1 2
      apps/app/src/stores/modal.tsx
  23. 0 9
      apps/app/src/styles/_editor.scss
  24. 31 6
      apps/app/src/styles/mixins/_editing.scss
  25. 1 1
      apps/slackbot-proxy/package.json
  26. 4 2
      package.json
  27. 3 3
      packages/editor/package.json
  28. 20 2
      packages/editor/src/components/CodeMirrorEditor/CodeMirrorEditor.module.scss
  29. 7 8
      packages/editor/src/components/CodeMirrorEditor/CodeMirrorEditor.tsx
  30. 3 3
      packages/editor/src/components/CodeMirrorEditor/Toolbar/AttachmentsDropdownItem.tsx
  31. 1 1
      packages/editor/src/components/CodeMirrorEditor/Toolbar/LinkEditButton.tsx
  32. 1 1
      packages/editor/src/components/CodeMirrorEditor/Toolbar/Toolbar.tsx
  33. 1 1
      packages/editor/src/components/CodeMirrorEditorMain.tsx
  34. 1 1
      packages/editor/src/components/CodeMirrorEditorReadOnly.tsx
  35. 2 2
      packages/editor/src/components/playground/Playground.tsx
  36. 4 3
      packages/editor/src/components/playground/PlaygroundController.tsx
  37. 2 1
      packages/editor/src/consts/editor-settings.ts
  38. 16 0
      packages/editor/src/consts/editor-themes.ts
  39. 2 0
      packages/editor/src/consts/index.ts
  40. 10 0
      packages/editor/src/consts/keymaps.ts
  41. 1 0
      packages/editor/src/index.ts
  42. 0 0
      packages/editor/src/models/index.ts
  43. 0 0
      packages/editor/src/models/markdown-table.d.ts
  44. 0 0
      packages/editor/src/models/markdown-table.js
  45. 0 0
      packages/editor/src/services-internal/editor-theme/.eslintrc.cjs
  46. 0 0
      packages/editor/src/services-internal/editor-theme/ayu.ts
  47. 0 0
      packages/editor/src/services-internal/editor-theme/cobalt.ts
  48. 0 0
      packages/editor/src/services-internal/editor-theme/eclipse.ts
  49. 3 18
      packages/editor/src/services-internal/editor-theme/index.ts
  50. 1 1
      packages/editor/src/services-internal/editor-theme/material.ts
  51. 1 1
      packages/editor/src/services-internal/editor-theme/nord.ts
  52. 0 0
      packages/editor/src/services-internal/editor-theme/original-dark.ts
  53. 1 1
      packages/editor/src/services-internal/editor-theme/original-light.ts
  54. 0 0
      packages/editor/src/services-internal/editor-theme/rose-pine.ts
  55. 0 0
      packages/editor/src/services-internal/extensions/emojiAutocompletionSettings.ts
  56. 2 0
      packages/editor/src/services-internal/extensions/index.ts
  57. 2 3
      packages/editor/src/services-internal/extensions/setDataLine.ts
  58. 0 0
      packages/editor/src/services-internal/file-dropzone/index.ts
  59. 19 0
      packages/editor/src/services-internal/file-dropzone/use-file-dropzone/FileDropzoneOverlay.tsx
  60. 2 2
      packages/editor/src/services-internal/file-dropzone/use-file-dropzone/use-file-dropzone.ts
  61. 8 0
      packages/editor/src/services-internal/index.ts
  62. 3 12
      packages/editor/src/services-internal/keymaps/index.ts
  63. 1 1
      packages/editor/src/services-internal/keymaps/vim.ts
  64. 1 1
      packages/editor/src/services-internal/link-util/Linker.ts
  65. 2 0
      packages/editor/src/services-internal/link-util/index.ts
  66. 1 1
      packages/editor/src/services-internal/link-util/markdown-link-util.ts
  67. 1 0
      packages/editor/src/services-internal/list-util/index.ts
  68. 1 1
      packages/editor/src/services-internal/list-util/insert-newline-continue-markup.ts
  69. 1 0
      packages/editor/src/services-internal/paste-util/index.ts
  70. 0 0
      packages/editor/src/services-internal/paste-util/paste-markdown-util.ts
  71. 2 0
      packages/editor/src/services-internal/table/index.ts
  72. 2 2
      packages/editor/src/services-internal/table/insert-new-row-to-table-markdown.ts
  73. 53 0
      packages/editor/src/services-internal/table/use-show-table-icon.ts
  74. 0 1
      packages/editor/src/services/codemirror-editor/index.ts
  75. 0 19
      packages/editor/src/services/file-dropzone/use-file-dropzone/FileDropzoneOverlay.tsx
  76. 1 4
      packages/editor/src/services/index.ts
  77. 1 0
      packages/editor/src/services/use-codemirror-editor/index.ts
  78. 4 3
      packages/editor/src/services/use-codemirror-editor/use-codemirror-editor.ts
  79. 3 2
      packages/editor/src/services/use-codemirror-editor/utils/append-extensions.ts
  80. 1 1
      packages/editor/src/services/use-codemirror-editor/utils/focus.ts
  81. 1 1
      packages/editor/src/services/use-codemirror-editor/utils/fold-drawio.ts
  82. 1 1
      packages/editor/src/services/use-codemirror-editor/utils/get-doc.ts
  83. 1 1
      packages/editor/src/services/use-codemirror-editor/utils/init-doc.ts
  84. 1 1
      packages/editor/src/services/use-codemirror-editor/utils/insert-markdown-elements.ts
  85. 3 2
      packages/editor/src/services/use-codemirror-editor/utils/insert-prefix.ts
  86. 1 1
      packages/editor/src/services/use-codemirror-editor/utils/insert-text.ts
  87. 1 1
      packages/editor/src/services/use-codemirror-editor/utils/replace-text.ts
  88. 1 1
      packages/editor/src/services/use-codemirror-editor/utils/set-caret-line.ts
  89. 1 2
      packages/editor/src/stores/codemirror-editor.ts
  90. 1 1
      packages/editor/src/stores/use-collaborative-editor-mode.ts
  91. 3 2
      packages/editor/src/stores/use-default-extensions.ts
  92. 8 6
      packages/editor/src/stores/use-editor-settings.ts
  93. 1 1
      packages/editor/src/stores/use-handsontable.ts
  94. 2 2
      packages/editor/src/stores/use-link-edit-modal.ts
  95. 1 1
      packages/editor/src/stores/use-resolved-theme.ts
  96. 1 0
      packages/editor/svg/table.svg
  97. 1 1
      packages/pluginkit/package.json
  98. 579 102
      yarn.lock

+ 11 - 0
.changeset/config.json

@@ -0,0 +1,11 @@
+{
+  "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
+  "changelog": ["@changesets/changelog-github", { "repo": "weseek/growi" }],
+  "commit": false,
+  "fixed": [],
+  "linked": [],
+  "access": "restricted",
+  "baseBranch": "master",
+  "updateInternalDependencies": "patch",
+  "ignore": []
+}

+ 1 - 0
.eslintrc.js

@@ -48,6 +48,7 @@ module.exports = {
         'newlines-between': 'always',
       },
     ],
+    '@typescript-eslint/consistent-type-imports': 'warn',
     '@typescript-eslint/no-explicit-any': 'off',
     '@typescript-eslint/explicit-module-boundary-types': 'off',
     indent: [

+ 18 - 1
CHANGELOG.md

@@ -1,9 +1,26 @@
 # Changelog
 
-## [Unreleased](https://github.com/weseek/growi/compare/v7.0.6...HEAD)
+## [Unreleased](https://github.com/weseek/growi/compare/v7.0.7...HEAD)
 
 *Please do not manually update this file. We've automated the process.*
 
+## [v7.0.7](https://github.com/weseek/growi/compare/v7.0.6...v7.0.7) - 2024-05-27
+
+### 🚀 Improvement
+
+* imprv: Behavior of dropdown toggle in groundglassbar (#8832) @maeshinshin
+* imprv: toastr location (#8831) @yuki-takei
+
+### 🐛 Bug Fixes
+
+* fix: Do not insert initial value when input is empty in editor (#8773) @miya
+
+### 🧰 Maintenance
+
+* support: Apply changesets (#8840) @yuki-takei
+* support: Upgrade yjs packages (#8839) @yuki-takei
+* support: Upgrade stylelint (#8835) @yuki-takei
+
 ## [v7.0.6](https://github.com/weseek/growi/compare/v7.0.5...v7.0.6) - 2024-05-20
 
 ### 🐛 Bug Fixes

+ 0 - 1
apps/app/.eslintrc.js

@@ -27,7 +27,6 @@ module.exports = {
       },
     ]],
     '@typescript-eslint/no-var-requires': 'off',
-    '@typescript-eslint/consistent-type-imports': 'warn',
 
     // set 'warn' temporarily -- 2021.08.02 Yuki Takei
     '@typescript-eslint/no-use-before-define': ['warn'],

+ 1 - 1
apps/app/docker/README.md

@@ -10,7 +10,7 @@ GROWI Official docker image
 Supported tags and respective Dockerfile links
 ------------------------------------------------
 
-* [`7.0.6`, `7.0`, `7`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v7.0.6/apps/app/docker/Dockerfile)
+* [`7.0.7`, `7.0`, `7`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v7.0.7/apps/app/docker/Dockerfile)
 * [`6.3.2`, `6.3`, `6` (Dockerfile)](https://github.com/weseek/growi/blob/v6.3.2/apps/app/docker/Dockerfile)
 * [`6.2.4`, `6.2` (Dockerfile)](https://github.com/weseek/growi/blob/v6.2.4/apps/app/docker/Dockerfile)
 * [`6.1.15`, `6.1` (Dockerfile)](https://github.com/weseek/growi/blob/v6.1.15/apps/app/docker/Dockerfile)

+ 6 - 6
apps/app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/app",
-  "version": "7.0.7-RC.0",
+  "version": "7.0.8-RC.0",
   "license": "MIT",
   "scripts": {
     "//// for production": "",
@@ -194,7 +194,7 @@
     "remark-toc": "^8.0.1",
     "remark-wiki-link": "^1.0.4",
     "sanitize-filename": "^1.6.3",
-    "socket.io": "^4.7.2",
+    "socket.io": "^4.7.5",
     "stream-to-promise": "^3.0.0",
     "string-width": "=4.2.2",
     "superjson": "^1.9.1",
@@ -210,9 +210,9 @@
     "validator": "^13.7.0",
     "ws": "^8.3.0",
     "xss": "^1.0.14",
-    "y-mongodb-provider": "^0.1.7",
-    "y-socket.io": "^1.1.0",
-    "yjs": "^13.6.12"
+    "y-mongodb-provider": "^0.1.10",
+    "y-socket.io": "^1.1.3",
+    "yjs": "^13.6.15"
   },
   "// comments for defDependencies": {
     "bootstrap": "v5.3.3 has a bug. refs: https://github.com/twbs/bootstrap/issues/39798",
@@ -280,7 +280,7 @@
     "sass": "^1.53.0",
     "simple-load-script": "^1.0.2",
     "simplebar-react": "^2.3.6",
-    "socket.io-client": "^4.2.0",
+    "socket.io-client": "^4.7.5",
     "source-map-loader": "^4.0.1",
     "swagger2openapi": "^7.0.8",
     "tsc-alias": "^1.2.9"

+ 0 - 147
apps/app/src/client/models/MarkdownTable.js

@@ -1,147 +0,0 @@
-import csvToMarkdown from 'csv-to-markdown-table';
-import { markdownTable } from 'markdown-table';
-import stringWidth from 'string-width';
-
-// https://github.com/markdown-it/markdown-it/blob/d29f421927e93e88daf75f22089a3e732e195bd2/lib/rules_block/table.js#L83
-// https://regex101.com/r/7BN2fR/7
-const tableAlignmentLineRE = /^[-:|][-:|\s]*$/;
-const tableAlignmentLineNegRE = /^[^-:]*$/; // it is need to check to ignore empty row which is matched above RE
-const linePartOfTableRE = /^\|[^\r\n]*|[^\r\n]*\|$|([^|\r\n]+\|[^|\r\n]*)+/; // own idea
-
-const defaultOptions = { stringLength: stringWidth };
-
-/**
- * markdown table class for markdown-table module
- *   ref. https://github.com/wooorm/markdown-table
- */
-export default class MarkdownTable {
-
-  constructor(table, options) {
-    this.table = table || [];
-    this.options = Object.assign(options || {}, defaultOptions);
-
-    this.toString = this.toString.bind(this);
-  }
-
-  toString() {
-    return markdownTable(this.table, this.options);
-  }
-
-  /**
-   * returns cloned Markdowntable instance
-   * (This method clones only the table field.)
-   */
-  clone() {
-    const newTable = [];
-    for (let i = 0; i < this.table.length; i++) {
-      newTable.push([].concat(this.table[i]));
-    }
-    return new MarkdownTable(newTable, this.options);
-  }
-
-  /**
-   * normalize all cell data(trim & convert the newline character to space or pad '' if cell data is null)
-   */
-  normalizeCells() {
-    for (let i = 0; i < this.table.length; i++) {
-      for (let j = 0; j < this.table[i].length; j++) {
-        if (this.table[i][j] != null) {
-          this.table[i][j] = this.table[i][j].trim().replace(/\r?\n/g, ' ');
-        }
-        else {
-          this.table[i][j] = '';
-        }
-      }
-    }
-
-    return this;
-  }
-
-  /**
-   * return a MarkdownTable instance made from a string of HTML table tag
-   *
-   * If a parser error occurs, an error object with an error message is thrown.
-   * The error message is a innerHTML, so must not assign it into element.innerHTML because it can lead to Mutation-based XSS
-   */
-  static fromHTMLTableTag(str) {
-    // set up DOMParser
-    const domParser = new (window.DOMParser)();
-
-    // use DOMParser to prevent DOM based XSS (https://developer.mozilla.org/en-US/docs/Web/API/DOMParser)
-    const dom = domParser.parseFromString(str, 'application/xml');
-
-    if (dom.querySelector('parsererror')) {
-      throw new Error(dom.documentElement.innerHTML);
-    }
-
-    const tableElement = dom.querySelector('table');
-    const trElements = tableElement.querySelectorAll('tr');
-
-    const table = [];
-    let maxRowSize = 0;
-    for (let i = 0; i < trElements.length; i++) {
-      const row = [];
-      const cellElements = trElements[i].querySelectorAll('th,td');
-      for (let j = 0; j < cellElements.length; j++) {
-        row.push(cellElements[j].innerHTML);
-      }
-      table.push(row);
-
-      if (maxRowSize < row.length) maxRowSize = row.length;
-    }
-
-    const align = [];
-    for (let i = 0; i < maxRowSize; i++) {
-      align.push('');
-    }
-
-    return new MarkdownTable(table, { align });
-  }
-
-  /**
-   * return a MarkdownTable instance made from a string of delimiter-separated values
-   */
-  static fromDSV(str, delimiter) {
-    return MarkdownTable.fromMarkdownString(csvToMarkdown(str, delimiter, true));
-  }
-
-  /**
-   * return a MarkdownTable instance
-   *   ref. https://github.com/wooorm/markdown-table
-   * @param {string} str markdown string
-   */
-  static fromMarkdownString(str) {
-    const arrMDTableLines = str.split(/(\r\n|\r|\n)/);
-    const contents = [];
-    let aligns = [];
-    for (let n = 0; n < arrMDTableLines.length; n++) {
-      const line = arrMDTableLines[n];
-
-      if (tableAlignmentLineRE.test(line) && !tableAlignmentLineNegRE.test(line)) {
-        // parse line which described alignment
-        const alignRuleRE = [
-          { align: 'c', regex: /^:-+:$/ },
-          { align: 'l', regex: /^:-+$/ },
-          { align: 'r', regex: /^-+:$/ },
-        ];
-        let lineText = '';
-        lineText = line.replace(/^\||\|$/g, ''); // strip off pipe charactor which is placed head of line and last of line.
-        lineText = lineText.replace(/\s*/g, '');
-        aligns = lineText.split(/\|/).map((col) => {
-          const rule = alignRuleRE.find((rule) => { return col.match(rule.regex) });
-          return (rule != null) ? rule.align : '';
-        });
-      }
-      else if (linePartOfTableRE.test(line)) {
-        // parse line whether header or body
-        let lineText = '';
-        lineText = line.replace(/\s*\|\s*/g, '|');
-        lineText = lineText.replace(/^\||\|$/g, ''); // strip off pipe charactor which is placed head of line and last of line.
-        const row = lineText.split(/\|/);
-        contents.push(row);
-      }
-    }
-    return (new MarkdownTable(contents, { align: aligns }));
-  }
-
-}

+ 1 - 1
apps/app/src/client/services/side-effects/handsontable-modal-launcher-for-view.ts

@@ -4,7 +4,7 @@ import type EventEmitter from 'events';
 
 import { Origin } from '@growi/core';
 
-import type MarkdownTable from '~/client/models/MarkdownTable';
+import type { MarkdownTable } from '@growi/editor';
 import { extractRemoteRevisionDataFromErrorObj, updatePage as _updatePage } from '~/client/services/update-page';
 import { getMarkdownTableFromLine, replaceMarkdownTableInMarkdown } from '~/components/Page/markdown-table-util-for-view';
 import { useShareLinkId } from '~/stores/context';

+ 28 - 0
apps/app/src/components/Layout/BasicLayout.module.scss

@@ -0,0 +1,28 @@
+@use '@growi/core-styles/scss/bootstrap/init' as bs;
+@use '~/styles/mixins';
+
+
+// for react-toastify
+.grw-basic-layout :global {
+  .Toastify .Toastify__toast-container {
+    top: 2.5em;
+
+    @include bs.media-breakpoint-down(md) {
+      top: 6.5em;
+    }
+  }
+}
+
+.grw-basic-layout {
+  @include mixins.with-editing() {
+    .Toastify .Toastify__toast-container {
+      top: 5em;
+
+      @include bs.media-breakpoint-down(md) {
+        top: 7em;
+      }
+    }
+  }
+}
+
+

+ 7 - 1
apps/app/src/components/Layout/BasicLayout.tsx

@@ -9,6 +9,12 @@ import { Sidebar } from '../Sidebar';
 
 import { RawLayout } from './RawLayout';
 
+
+import styles from './BasicLayout.module.scss';
+
+const moduleClass = styles['grw-basic-layout'] ?? '';
+
+
 const AlertSiteUrlUndefined = dynamic(() => import('../AlertSiteUrlUndefined').then(mod => mod.AlertSiteUrlUndefined), { ssr: false });
 const DeleteAttachmentModal = dynamic(() => import('../PageAttachment/DeleteAttachmentModal').then(mod => mod.DeleteAttachmentModal), { ssr: false });
 const HotkeysManager = dynamic(() => import('../Hotkeys/HotkeysManager'), { ssr: false });
@@ -35,7 +41,7 @@ type Props = {
 
 export const BasicLayout = ({ children, className }: Props): JSX.Element => {
   return (
-    <RawLayout className={`${className ?? ''}`}>
+    <RawLayout className={`${moduleClass} ${className ?? ''}`}>
       <DndProvider backend={HTML5Backend}>
 
         <div className="page-wrapper flex-row">

+ 1 - 1
apps/app/src/components/Navbar/GrowiContextualSubNavigation.module.scss

@@ -9,7 +9,7 @@
   }
 }
 
-@include mixins.editing {
+@include mixins.at-editing() {
   .grw-contextual-sub-navigation {
     position: fixed;
     right: 0;

+ 1 - 1
apps/app/src/components/Page/markdown-table-util-for-view.ts

@@ -1,4 +1,4 @@
-import MarkdownTable from '~/client/models/MarkdownTable';
+import { MarkdownTable } from '@growi/editor';
 
 export const getMarkdownTableFromLine = (markdown: string, bol: number, eol: number): MarkdownTable => {
   const tableLines = markdown.split(/\r\n|\r|\n/).slice(bol - 1, eol).join('\n');

+ 15 - 10
apps/app/src/components/PageControls/PageControls.tsx

@@ -66,7 +66,7 @@ const Tags = (props: TagsProps): JSX.Element => {
 };
 
 type WideViewMenuItemProps = AdditionalMenuItemsRendererProps & {
-  onClickMenuItem: (newValue: boolean) => void,
+  onClickMenuItem: () => void,
   expandContentWidth?: boolean,
 }
 
@@ -77,24 +77,27 @@ const WideViewMenuItem = (props: WideViewMenuItemProps): JSX.Element => {
     onClickMenuItem, expandContentWidth,
   } = props;
 
+  const menuItemClickedHandler = useCallback((e: React.MouseEvent<HTMLInputElement>) => {
+    e.preventDefault();
+    onClickMenuItem();
+  }, [onClickMenuItem]);
+
   return (
-    <DropdownItem
-      onClick={() => onClickMenuItem(!(expandContentWidth))}
-      className="grw-page-control-dropdown-item"
+    <div
+      className="grw-page-control-dropdown-item dropdown-item"
+      onClick={menuItemClickedHandler}
     >
       <div className="form-check form-switch ms-1">
         <input
-          id="switchContentWidth"
           className="form-check-input"
           type="checkbox"
           checked={expandContentWidth}
-          onChange={() => {}}
         />
-        <label className="form-label form-check-label" htmlFor="switchContentWidth">
+        <label className="form-label form-check-label">
           { t('wide_view') }
         </label>
       </div>
-    </DropdownItem>
+    </div>
   );
 };
 
@@ -225,7 +228,9 @@ const PageControlsSubstance = (props: PageControlsSubstanceProps): JSX.Element =
     onClickDeleteMenuItem(pageToDelete);
   }, [onClickDeleteMenuItem, pageId, pageInfo, path, revisionId]);
 
-  const switchContentWidthClickHandler = useCallback(async(newValue: boolean) => {
+  const switchContentWidthClickHandler = useCallback(() => {
+
+    const newValue = !expandContentWidth;
     if (onClickSwitchContentWidth == null || (isGuestUser ?? true) || (isReadOnlyUser ?? true)) {
       logger.warn('Could not switch content width', {
         onClickSwitchContentWidth: onClickSwitchContentWidth == null ? 'null' : 'not null',
@@ -243,7 +248,7 @@ const PageControlsSubstance = (props: PageControlsSubstanceProps): JSX.Element =
     catch (err) {
       toastError(err);
     }
-  }, [isGuestUser, isReadOnlyUser, onClickSwitchContentWidth, pageId, pageInfo]);
+  }, [expandContentWidth, isGuestUser, isReadOnlyUser, onClickSwitchContentWidth, pageId, pageInfo]);
 
   const additionalMenuItemOnTopRenderer = useMemo(() => {
     if (!isIPageInfoForEntity(pageInfo)) {

+ 1 - 1
apps/app/src/components/PageEditor/EditorNavbarBottom.module.scss

@@ -2,7 +2,7 @@
 @use '~/styles/variables' as var;
 @use '~/styles/mixins';
 
-@include mixins.editing {
+@include mixins.at-editing() {
   .grw-editor-navbar-bottom :global {
     .grw-grant-selector {
       max-width: 250px;

+ 1 - 1
apps/app/src/components/PageEditor/HandsontableModal.tsx

@@ -1,5 +1,6 @@
 import React, { useState } from 'react';
 
+import { MarkdownTable } from '@growi/editor';
 import { useHandsontableModalForEditor } from '@growi/editor/src/stores/use-handsontable';
 import { HotTable } from '@handsontable/react';
 import type Handsontable from 'handsontable';
@@ -10,7 +11,6 @@ import {
 } from 'reactstrap';
 import { debounce } from 'throttle-debounce';
 
-import MarkdownTable from '~/client/models/MarkdownTable';
 import { replaceFocusedMarkdownTableWithEditor, getMarkdownTable } from '~/components/PageEditor/markdown-table-util-for-editor';
 import { useHandsontableModal } from '~/stores/modal';
 

+ 1 - 1
apps/app/src/components/PageEditor/LinkEditModal.tsx

@@ -2,7 +2,7 @@ import React, { useEffect, useState, useCallback } from 'react';
 
 import path from 'path';
 
-import Linker from '@growi/editor/src/services/link-util/Linker';
+import { Linker } from '@growi/editor/src/services-internal';
 import { useLinkEditModal } from '@growi/editor/src/stores/use-link-edit-modal';
 import { useTranslation } from 'next-i18next';
 import {

+ 1 - 1
apps/app/src/components/PageEditor/MarkdownTableDataImportForm.tsx

@@ -1,12 +1,12 @@
 import React, { useState } from 'react';
 
+import { MarkdownTable } from '@growi/editor';
 import { useTranslation } from 'next-i18next';
 import {
   Button,
   Collapse,
 } from 'reactstrap';
 
-import MarkdownTable from '~/client/models/MarkdownTable';
 
 type MarkdownTableDataImportFormProps = {
   onCancel: () => void,

+ 4 - 3
apps/app/src/components/PageEditor/PageEditor.tsx

@@ -149,7 +149,10 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     // set to ref
     initialValueRef.current = initialValue;
   }, [initialValue]);
-  const [markdownToPreview, setMarkdownToPreview] = useState<string>(initialValue);
+
+  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
+
+  const [markdownToPreview, setMarkdownToPreview] = useState<string>(codeMirrorEditor?.getDoc() ?? '');
   const setMarkdownPreviewWithDebounce = useMemo(() => debounce(100, throttle(150, (value: string) => {
     setMarkdownToPreview(value);
   })), []);
@@ -159,8 +162,6 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
   }, [setMarkdownPreviewWithDebounce]);
 
 
-  const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
-
   const { scrollEditorHandler, scrollPreviewHandler } = useScrollSync(GlobalCodeMirrorEditorKey.MAIN, previewRef);
 
   const scrollEditorHandlerThrottle = useMemo(() => throttle(25, scrollEditorHandler), [scrollEditorHandler]);

+ 1 - 2
apps/app/src/components/PageEditor/markdown-table-util-for-editor.ts

@@ -1,6 +1,5 @@
 import type { EditorView } from '@codemirror/view';
-
-import MarkdownTable from '~/client/models/MarkdownTable';
+import { MarkdownTable } from '@growi/editor';
 
 // https://regex101.com/r/7BN2fR/10
 const linePartOfTableRE = /^([^\r\n|]*)\|(([^\r\n|]*\|)+)$/;

+ 1 - 1
apps/app/src/components/Sidebar/SidebarHead/ToggleCollapseButton.module.scss

@@ -24,7 +24,7 @@
 }
 
 // Hide when editing
-@include mixins.editing {
+@include mixins.at-editing() {
   .btn-toggle-collapse {
     visibility: hidden;
   }

+ 3 - 4
apps/app/src/server/service/yjs-connection-manager.ts

@@ -59,10 +59,9 @@ class YjsConnectionManager {
 
     await this.mdb.flushDocument(pageId);
 
-    const persistedCodeMirrorText = persistedYdoc.getText('codemirror').toString();
-    const currentCodeMirrorText = currentYdoc.getText('codemirror').toString();
-
-    if (persistedCodeMirrorText === '' && currentCodeMirrorText === '') {
+    // If no write operation has been performed, insert initial value
+    const clientsSize = currentYdoc.store.clients.size;
+    if (clientsSize === 0) {
       currentYdoc.getText('codemirror').insert(0, initialValue);
     }
 

+ 1 - 2
apps/app/src/stores/modal.tsx

@@ -4,10 +4,9 @@ import type {
   IAttachmentHasId, IPageToDeleteWithMeta, IPageToRenameWithMeta, IUserGroupHasId,
 } from '@growi/core';
 import { useSWRStatic } from '@growi/core/dist/swr';
+import { MarkdownTable } from '@growi/editor';
 import type { SWRResponse } from 'swr';
 
-
-import MarkdownTable from '~/client/models/MarkdownTable';
 import type { BookmarkFolderItems } from '~/interfaces/bookmark-info';
 import type {
   OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction, OnPutBackedFunction, onDeletedBookmarkFolderFunction, OnSelectedFunction,

+ 0 - 9
apps/app/src/styles/_editor.scss

@@ -97,15 +97,6 @@
 
   }
 
-  // .builtin-editor .tab-pane#edit
-
-  /*****************
-   *     Toastr
-   *****************/
-  .Toastify .Toastify__toast-container {
-    top: 4.5em;
-  }
-
 }
 
 // TODO: Never used this id class

+ 31 - 6
apps/app/src/styles/mixins/_editing.scss

@@ -1,13 +1,38 @@
-@mixin editing($global: false) {
+/**
+ * USAGE:
+ * @include at-editing() {
+ *   .component-class {
+ *     visibility: hidden;
+ *   }
+ * }
+ *
+ * outputs: .layout-root.editing .component-class_LOCAL_ID { visibility: hidden; }
+ */
+@mixin at-editing() {
   :global {
     .layout-root.editing {
-      @if $global {
+      :local {
         @content;
-      } @else {
-        :local {
-          @content;
-        }
       }
     }
   }
 }
+
+/**
+ * USAGE:
+ * .component-class {
+ *   @include with-editing() {
+ *     visibility: hidden;
+ *   }
+ * }
+ *
+ * outputs: .component-class_LOCAL_ID.layout-root.editing { visibility: hidden; }
+ */
+
+@mixin with-editing() {
+  &:global {
+    &.layout-root.editing {
+      @content;
+    }
+  }
+}

+ 1 - 1
apps/slackbot-proxy/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/slackbot-proxy",
-  "version": "7.0.7-slackbot-proxy.0",
+  "version": "7.0.8-slackbot-proxy.0",
   "license": "MIT",
   "scripts": {
     "build": "yarn tsc && tsc-alias -p tsconfig.build.json",

+ 4 - 2
package.json

@@ -1,6 +1,6 @@
 {
   "name": "growi",
-  "version": "7.0.7-RC.0",
+  "version": "7.0.8-RC.0",
   "description": "Team collaboration software using markdown",
   "license": "MIT",
   "private": "true",
@@ -48,6 +48,8 @@
     "yargs": "^17.7.1"
   },
   "devDependencies": {
+    "@changesets/changelog-github": "^0.5.0",
+    "@changesets/cli": "^2.27.3",
     "@swc-node/register": "^1.6.2",
     "@swc/core": "^1.3.36",
     "@swc/helpers": "^0.4.14",
@@ -83,8 +85,8 @@
     "rollup-plugin-node-externals": "^6.1.1",
     "shx": "^0.3.4",
     "stylelint": "^16.5.0",
-    "stylelint-config-recommended-scss": "^14.0.0",
     "stylelint-config-recess-order": "^5.0.1",
+    "stylelint-config-recommended-scss": "^14.0.0",
     "ts-node-dev": "^2.0.0",
     "tsconfig-paths": "^3.9.0",
     "typescript": "~5.0.0",

+ 3 - 3
packages/editor/package.json

@@ -61,8 +61,8 @@
     "string-width": "=4.2.2",
     "swr": "^2.2.2",
     "ts-deepmerge": "^6.2.0",
-    "y-codemirror.next": "^0.3.2",
-    "y-socket.io": "^1.1.0",
-    "yjs": "^13.6.12"
+    "y-codemirror.next": "^0.3.3",
+    "y-socket.io": "^1.1.3",
+    "yjs": "^13.6.15"
   }
 }

+ 20 - 2
packages/editor/src/components/CodeMirrorEditor/CodeMirrorEditor.module.scss

@@ -43,7 +43,6 @@
 
 }
 
-
 @mixin insertMaterialSymbolAndMessage($code, $message) {
   .overlay-icon:before {
     margin-right: 0.2em;
@@ -138,5 +137,24 @@
     }
     /* end of.dropzone */
   }
-}
 
+  .markdown-table-activated .cm-cursor {
+    &:after {
+      position: relative;
+      top: 0em;
+      left: 0.3em;
+      display: block;
+      width: 1em;
+      height: 1em;
+      content: ' ';
+      background-repeat: no-repeat;
+      background-size: 1em;
+    }
+  }
+
+  .markdown-table-activated .cm-cursor.cm-cursor-primary {
+    &:after {
+      background-image: url(../../../svg/table.svg);
+    }
+  }
+}

+ 7 - 8
packages/editor/src/components/CodeMirrorEditor/CodeMirrorEditor.tsx

@@ -1,6 +1,6 @@
+import type { DetailedHTMLProps } from 'react';
 import {
   forwardRef, useMemo, useRef, useEffect,
-  DetailedHTMLProps,
 } from 'react';
 
 import { indentUnit } from '@codemirror/language';
@@ -10,13 +10,11 @@ import {
 import { AcceptedUploadFileType } from '@growi/core';
 import type { ReactCodeMirrorProps } from '@uiw/react-codemirror';
 
-import { EditorSettings, GlobalCodeMirrorEditorKey } from '../../consts';
+import type { EditorSettings, GlobalCodeMirrorEditorKey } from '../../consts';
 import {
   useFileDropzone, FileDropzoneOverlay,
-} from '../../services';
-import {
-  adjustPasteData, getStrFromBol,
-} from '../../services/paste-util/paste-markdown-util';
+  adjustPasteData, getStrFromBol, useShowTableIcon,
+} from '../../services-internal';
 import { useDefaultExtensions, useCodeMirrorEditorIsolated, useEditorSettings } from '../../stores';
 
 import { Toolbar } from './Toolbar';
@@ -74,6 +72,8 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
   useDefaultExtensions(codeMirrorEditor);
   useEditorSettings(codeMirrorEditor, editorSettings, onSave);
 
+  useShowTableIcon(codeMirrorEditor);
+
   useEffect(() => {
     if (indentSize == null) {
       return;
@@ -159,7 +159,6 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
 
   }, [onScroll, codeMirrorEditor]);
 
-
   const {
     getRootProps,
     getInputProps,
@@ -211,7 +210,7 @@ export const CodeMirrorEditor = (props: Props): JSX.Element => {
 
   return (
     <div className={`${style['codemirror-editor']} flex-expand-vert overflow-y-hidden`}>
-      <div {...getRootProps()} className={`dropzone ${fileUploadState} flex-expand-vert`}>
+      <div {...getRootProps()} className={`dropzone  ${fileUploadState} flex-expand-vert`}>
         <input {...getInputProps()} />
         <FileDropzoneOverlay isEnabled={isDragActive} />
         <CodeMirrorEditorContainer ref={containerRef} />

+ 3 - 3
packages/editor/src/components/CodeMirrorEditor/Toolbar/AttachmentsDropdownItem.tsx

@@ -1,11 +1,11 @@
-import { ReactNode } from 'react';
+import type { ReactNode } from 'react';
 
-import { AcceptedUploadFileType } from '@growi/core';
+import type { AcceptedUploadFileType } from '@growi/core';
 import {
   DropdownItem,
 } from 'reactstrap';
 
-import { useFileDropzone } from '../../../services';
+import { useFileDropzone } from '../../../services-internal';
 
 type Props = {
   acceptedUploadFileType: AcceptedUploadFileType,

+ 1 - 1
packages/editor/src/components/CodeMirrorEditor/Toolbar/LinkEditButton.tsx

@@ -3,7 +3,7 @@ import { useCallback } from 'react';
 import { DropdownItem } from 'reactstrap';
 
 import type { GlobalCodeMirrorEditorKey } from '../../../consts';
-import { getMarkdownLink, replaceFocusedMarkdownLinkWithEditor } from '../../../services/link-util/markdown-link-util';
+import { getMarkdownLink, replaceFocusedMarkdownLinkWithEditor } from '../../../services-internal';
 import { useCodeMirrorEditorIsolated } from '../../../stores';
 import { useLinkEditModal } from '../../../stores/use-link-edit-modal';
 

+ 1 - 1
packages/editor/src/components/CodeMirrorEditor/Toolbar/Toolbar.tsx

@@ -1,6 +1,6 @@
 import { memo } from 'react';
 
-import { AcceptedUploadFileType } from '@growi/core';
+import type { AcceptedUploadFileType } from '@growi/core';
 
 import type { GlobalCodeMirrorEditorKey } from '../../../consts';
 

+ 1 - 1
packages/editor/src/components/CodeMirrorEditorMain.tsx

@@ -5,7 +5,7 @@ import { keymap, scrollPastEnd } from '@codemirror/view';
 import type { IUserHasId } from '@growi/core/dist/interfaces';
 
 import { GlobalCodeMirrorEditorKey } from '../consts';
-import { setDataLine } from '../services/extensions/setDataLine';
+import { setDataLine } from '../services-internal';
 import { useCodeMirrorEditorIsolated, useCollaborativeEditorMode } from '../stores';
 
 import { CodeMirrorEditor, type CodeMirrorEditorProps } from '.';

+ 1 - 1
packages/editor/src/components/CodeMirrorEditorReadOnly.tsx

@@ -3,7 +3,7 @@ import { useEffect } from 'react';
 import { type Extension, EditorState } from '@codemirror/state';
 
 import { GlobalCodeMirrorEditorKey } from '../consts';
-import { setDataLine } from '../services/extensions/setDataLine';
+import { setDataLine } from '../services-internal';
 import { useCodeMirrorEditorIsolated } from '../stores';
 
 import { CodeMirrorEditor } from '.';

+ 2 - 2
packages/editor/src/components/playground/Playground.tsx

@@ -5,8 +5,8 @@ import {
 import { AcceptedUploadFileType } from '@growi/core';
 import { toast } from 'react-toastify';
 
-import { EditorSettings, GlobalCodeMirrorEditorKey } from '../../consts';
-import type { EditorTheme, KeyMapMode } from '../../services';
+import { GlobalCodeMirrorEditorKey } from '../../consts';
+import type { EditorSettings, EditorTheme, KeyMapMode } from '../../consts';
 import { useCodeMirrorEditorIsolated } from '../../stores';
 import { CodeMirrorEditorMain } from '../CodeMirrorEditorMain';
 

+ 4 - 3
packages/editor/src/components/playground/PlaygroundController.tsx

@@ -2,10 +2,11 @@ import { useCallback } from 'react';
 
 import { useForm } from 'react-hook-form';
 
-import { GlobalCodeMirrorEditorKey } from '../../consts';
+import type { EditorTheme, KeyMapMode } from '../../consts';
 import {
-  AllEditorTheme, AllKeyMap, EditorTheme, KeyMapMode,
-} from '../../services';
+  GlobalCodeMirrorEditorKey,
+  AllEditorTheme, AllKeyMap,
+} from '../../consts';
 import { useCodeMirrorEditorIsolated } from '../../stores';
 
 export const InitEditorValueRow = (): JSX.Element => {

+ 2 - 1
packages/editor/src/consts/editor-settings.ts

@@ -1,4 +1,5 @@
-import { EditorTheme, KeyMapMode } from '../services';
+import type { EditorTheme } from './editor-themes';
+import type { KeyMapMode } from './keymaps';
 
 export interface EditorSettings {
   theme: undefined | EditorTheme,

+ 16 - 0
packages/editor/src/consts/editor-themes.ts

@@ -0,0 +1,16 @@
+const EditorTheme = {
+  defaultlight: 'defaultlight',
+  eclipse: 'eclipse',
+  basic: 'basic',
+  ayu: 'ayu',
+  rosepine:  'rosepine',
+  defaultdark: 'defaultdark',
+  material: 'material',
+  nord: 'nord',
+  cobalt: 'cobalt',
+  kimbie: 'kimbie',
+} as const;
+
+export const DEFAULT_THEME = 'defaultlight';
+export const AllEditorTheme = Object.values(EditorTheme);
+export type EditorTheme = typeof EditorTheme[keyof typeof EditorTheme];

+ 2 - 0
packages/editor/src/consts/index.ts

@@ -1,3 +1,5 @@
 export * from './global-code-mirror-editor-key';
 export * from './ydoc-awareness-user-color';
 export * from './editor-settings';
+export * from './editor-themes';
+export * from './keymaps';

+ 10 - 0
packages/editor/src/consts/keymaps.ts

@@ -0,0 +1,10 @@
+const KeyMapMode = {
+  default: 'default',
+  vim: 'vim',
+  emacs: 'emacs',
+  vscode: 'vscode',
+} as const;
+
+export const DEFAULT_KEYMAP = 'default';
+export const AllKeyMap = Object.values(KeyMapMode);
+export type KeyMapMode = typeof KeyMapMode[keyof typeof KeyMapMode];

+ 1 - 0
packages/editor/src/index.ts

@@ -1,4 +1,5 @@
 export * from './components';
 export * from './consts';
+export * from './models';
 export * from './services';
 export * from './stores';

+ 0 - 0
packages/editor/src/services/table-util/index.ts → packages/editor/src/models/index.ts


+ 0 - 0
packages/editor/src/services/table-util/markdown-table.d.ts → packages/editor/src/models/markdown-table.d.ts


+ 0 - 0
packages/editor/src/services/table-util/markdown-table.js → packages/editor/src/models/markdown-table.js


+ 0 - 0
packages/editor/src/services/editor-theme/.eslintrc.cjs → packages/editor/src/services-internal/editor-theme/.eslintrc.cjs


+ 0 - 0
packages/editor/src/services/editor-theme/ayu.ts → packages/editor/src/services-internal/editor-theme/ayu.ts


+ 0 - 0
packages/editor/src/services/editor-theme/cobalt.ts → packages/editor/src/services-internal/editor-theme/cobalt.ts


+ 0 - 0
packages/editor/src/services/editor-theme/eclipse.ts → packages/editor/src/services-internal/editor-theme/eclipse.ts


+ 3 - 18
packages/editor/src/services/editor-theme/index.ts → packages/editor/src/services-internal/editor-theme/index.ts

@@ -1,4 +1,6 @@
-import { Extension } from '@codemirror/state';
+import type { Extension } from '@codemirror/state';
+
+import type { EditorTheme } from '../../consts';
 
 export const getEditorTheme = async(themeName?: EditorTheme): Promise<Extension> => {
   switch (themeName) {
@@ -23,20 +25,3 @@ export const getEditorTheme = async(themeName?: EditorTheme): Promise<Extension>
   }
   return (await import('./original-light')).originalLight;
 };
-
-const EditorTheme = {
-  defaultlight: 'defaultlight',
-  eclipse: 'eclipse',
-  basic: 'basic',
-  ayu: 'ayu',
-  rosepine:  'rosepine',
-  defaultdark: 'defaultdark',
-  material: 'material',
-  nord: 'nord',
-  cobalt: 'cobalt',
-  kimbie: 'kimbie',
-} as const;
-
-export const DEFAULT_THEME = 'defaultlight';
-export const AllEditorTheme = Object.values(EditorTheme);
-export type EditorTheme = typeof EditorTheme[keyof typeof EditorTheme]

+ 1 - 1
packages/editor/src/services/editor-theme/material.ts → packages/editor/src/services-internal/editor-theme/material.ts

@@ -1,6 +1,6 @@
 // Ref: https://github.com/craftzdog/cm6-themes/blob/289d9e0ca6b500f4cdf68464f4f21dd8e2dd8963/packages/material-dark/src/index.ts
 import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';
-import { Extension } from '@codemirror/state';
+import type { Extension } from '@codemirror/state';
 import { EditorView } from '@codemirror/view';
 import { tags as t } from '@lezer/highlight';
 

+ 1 - 1
packages/editor/src/services/editor-theme/nord.ts → packages/editor/src/services-internal/editor-theme/nord.ts

@@ -1,7 +1,7 @@
 // Ref: https://github.com/craftzdog/cm6-themes/blob/221936c525dcfc05b298cc4d4a0ba284cb7c7138/packages/nord/src/index.ts
 
 import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';
-import { Extension } from '@codemirror/state';
+import type { Extension } from '@codemirror/state';
 import { EditorView } from '@codemirror/view';
 import { tags as t } from '@lezer/highlight';
 

+ 0 - 0
packages/editor/src/services/editor-theme/original-dark.ts → packages/editor/src/services-internal/editor-theme/original-dark.ts


+ 1 - 1
packages/editor/src/services/editor-theme/original-light.ts → packages/editor/src/services-internal/editor-theme/original-light.ts

@@ -1,6 +1,6 @@
 // Ref: https://github.com/uiwjs/react-codemirror/blob/bf3b862923d0cb04ccf4bb9da0791bdc7fd6d29b/themes/github/src/index.ts
 
-import { Extension } from '@codemirror/state';
+import type { Extension } from '@codemirror/state';
 import { tags as t } from '@lezer/highlight';
 import { createTheme } from '@uiw/codemirror-themes';
 

+ 0 - 0
packages/editor/src/services/editor-theme/rose-pine.ts → packages/editor/src/services-internal/editor-theme/rose-pine.ts


+ 0 - 0
packages/editor/src/services/extensions/emojiAutocompletionSettings.ts → packages/editor/src/services-internal/extensions/emojiAutocompletionSettings.ts


+ 2 - 0
packages/editor/src/services-internal/extensions/index.ts

@@ -0,0 +1,2 @@
+export * from './emojiAutocompletionSettings';
+export * from './setDataLine';

+ 2 - 3
packages/editor/src/services/extensions/setDataLine.ts → packages/editor/src/services-internal/extensions/setDataLine.ts

@@ -3,9 +3,8 @@
 
 
 import { RangeSetBuilder } from '@codemirror/state';
-import {
-  EditorView, Decoration, ViewPlugin, DecorationSet, ViewUpdate,
-} from '@codemirror/view';
+import type { EditorView, DecorationSet, ViewUpdate } from '@codemirror/view';
+import { Decoration, ViewPlugin } from '@codemirror/view';
 
 const stripeDeco = (view: EditorView) => {
   const builder = new RangeSetBuilder<Decoration>();

+ 0 - 0
packages/editor/src/services/file-dropzone/index.ts → packages/editor/src/services-internal/file-dropzone/index.ts


+ 19 - 0
packages/editor/src/services-internal/file-dropzone/use-file-dropzone/FileDropzoneOverlay.tsx

@@ -0,0 +1,19 @@
+type Props = {
+  isEnabled: boolean,
+}
+
+export const FileDropzoneOverlay = (props: Props): JSX.Element => {
+  const { isEnabled } = props;
+
+  if (isEnabled) {
+    return (
+      <div className="overlay overlay-dropzone-active">
+        <span className="overlay-content">
+          <span className="overlay-icon material-symbols-outlined">
+          </span>
+        </span>
+      </div>
+    );
+  }
+  return <></>;
+};

+ 2 - 2
packages/editor/src/services/file-dropzone/use-file-dropzone/use-file-dropzone.ts → packages/editor/src/services-internal/file-dropzone/use-file-dropzone/use-file-dropzone.ts

@@ -1,8 +1,8 @@
 import { useCallback, useState } from 'react';
 
 import { AcceptedUploadFileType } from '@growi/core';
-import { useDropzone, Accept } from 'react-dropzone';
-import type { DropzoneOptions, DropzoneState } from 'react-dropzone';
+import { useDropzone } from 'react-dropzone';
+import type { DropzoneOptions, DropzoneState, Accept } from 'react-dropzone';
 
 
 type FileDropzoneState = DropzoneState & {

+ 8 - 0
packages/editor/src/services-internal/index.ts

@@ -0,0 +1,8 @@
+export * from './editor-theme';
+export * from './extensions';
+export * from './file-dropzone';
+export * from './keymaps';
+export * from './link-util';
+export * from './list-util';
+export * from './paste-util';
+export * from './table';

+ 3 - 12
packages/editor/src/services/keymaps/index.ts → packages/editor/src/services-internal/keymaps/index.ts

@@ -1,6 +1,8 @@
-import { Extension } from '@codemirror/state';
+import type { Extension } from '@codemirror/state';
 import { keymap } from '@codemirror/view';
 
+import type { KeyMapMode } from '../../consts';
+
 
 export const getKeymap = async(keyMapName?: KeyMapMode, onSave?: () => void): Promise<Extension> => {
   switch (keyMapName) {
@@ -13,14 +15,3 @@ export const getKeymap = async(keyMapName?: KeyMapMode, onSave?: () => void): Pr
   }
   return keymap.of((await import('@codemirror/commands')).defaultKeymap);
 };
-
-const KeyMapMode = {
-  default: 'default',
-  vim: 'vim',
-  emacs: 'emacs',
-  vscode: 'vscode',
-} as const;
-
-export const DEFAULT_KEYMAP = 'default';
-export const AllKeyMap = Object.values(KeyMapMode);
-export type KeyMapMode = typeof KeyMapMode[keyof typeof KeyMapMode];

+ 1 - 1
packages/editor/src/services/keymaps/vim.ts → packages/editor/src/services-internal/keymaps/vim.ts

@@ -1,4 +1,4 @@
-import { Extension } from '@codemirror/state';
+import type { Extension } from '@codemirror/state';
 import { Vim, vim } from '@replit/codemirror-vim';
 
 // vim useful keymap custom

+ 1 - 1
packages/editor/src/services/link-util/Linker.ts → packages/editor/src/services-internal/link-util/Linker.ts

@@ -1,6 +1,6 @@
 import { encodeSpaces } from '@growi/core/dist/utils/page-path-utils';
 
-export default class Linker {
+export class Linker {
 
   type: string;
 

+ 2 - 0
packages/editor/src/services-internal/link-util/index.ts

@@ -0,0 +1,2 @@
+export * from './Linker';
+export * from './markdown-link-util';

+ 1 - 1
packages/editor/src/services/link-util/markdown-link-util.ts → packages/editor/src/services-internal/link-util/markdown-link-util.ts

@@ -1,6 +1,6 @@
 import type { EditorView } from '@codemirror/view';
 
-import Linker from './Linker';
+import { Linker } from './Linker';
 
 const curPos = (editor: EditorView) => {
   return editor.state.selection.main.head;

+ 1 - 0
packages/editor/src/services-internal/list-util/index.ts

@@ -0,0 +1 @@
+export * from './insert-newline-continue-markup';

+ 1 - 1
packages/editor/src/services/list-util/insert-newline-continue-markup.ts → packages/editor/src/services-internal/list-util/insert-newline-continue-markup.ts

@@ -1,5 +1,5 @@
 import type { ChangeSpec } from '@codemirror/state';
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@codemirror/view';
 
 // https://regex101.com/r/r9plEA/1
 const indentAndMarkRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]\s))(\s*)/;

+ 1 - 0
packages/editor/src/services-internal/paste-util/index.ts

@@ -0,0 +1 @@
+export * from './paste-markdown-util';

+ 0 - 0
packages/editor/src/services/paste-util/paste-markdown-util.ts → packages/editor/src/services-internal/paste-util/paste-markdown-util.ts


+ 2 - 0
packages/editor/src/services-internal/table/index.ts

@@ -0,0 +1,2 @@
+export * from './insert-new-row-to-table-markdown';
+export * from './use-show-table-icon';

+ 2 - 2
packages/editor/src/services/table-util/insert-new-row-to-table-markdown.ts → packages/editor/src/services-internal/table/insert-new-row-to-table-markdown.ts

@@ -1,6 +1,6 @@
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@codemirror/view';
 
-import { MarkdownTable } from './markdown-table';
+import { MarkdownTable } from '../../models';
 
 // https://regex101.com/r/7BN2fR/10
 const linePartOfTableRE = /^([^\r\n|]*)\|(([^\r\n|]*\|)+)$/;

+ 53 - 0
packages/editor/src/services-internal/table/use-show-table-icon.ts

@@ -0,0 +1,53 @@
+import { useEffect, useState } from 'react';
+
+import type { ViewUpdate } from '@codemirror/view';
+import { EditorView } from 'codemirror';
+
+
+import type { UseCodeMirrorEditor } from '../../services';
+
+import { isInTable } from './insert-new-row-to-table-markdown';
+
+const markdownTableActivatedClass = 'markdown-table-activated';
+
+export const useShowTableIcon = (codeMirrorEditor?: UseCodeMirrorEditor): void => {
+
+  const [editorClass, setEditorClass] = useState('');
+
+  const editor = codeMirrorEditor?.view;
+
+  useEffect(() => {
+
+    const handleFocusChanged = () => {
+      if (editor == null) {
+        return;
+      }
+      if (isInTable(editor)) {
+        setEditorClass(markdownTableActivatedClass);
+      }
+      else {
+        setEditorClass('');
+      }
+    };
+
+    const cleanupFunction = codeMirrorEditor?.appendExtensions(
+      EditorView.updateListener.of((v: ViewUpdate) => {
+        if (v.transactions.some(tr => tr.selection || tr.docChanged)) {
+          handleFocusChanged();
+        }
+      }),
+    );
+
+    return cleanupFunction;
+
+  }, [codeMirrorEditor, editor]);
+
+  useEffect(() => {
+    const cleanupFunction = codeMirrorEditor?.appendExtensions(
+      EditorView.editorAttributes.of({ class: editorClass }),
+    );
+
+    return cleanupFunction;
+  }, [codeMirrorEditor, editorClass]);
+
+};

+ 0 - 1
packages/editor/src/services/codemirror-editor/index.ts

@@ -1 +0,0 @@
-export * from './use-codemirror-editor/use-codemirror-editor';

+ 0 - 19
packages/editor/src/services/file-dropzone/use-file-dropzone/FileDropzoneOverlay.tsx

@@ -1,19 +0,0 @@
-type Props = {
-  isEnabled: boolean,
-}
-
-export const FileDropzoneOverlay = (props: Props) => {
-  const { isEnabled } = props;
-
-    if (isEnabled) {
-      return (
-        <div className="overlay overlay-dropzone-active">
-          <span className="overlay-content">
-            <span className="overlay-icon material-symbols-outlined">
-            </span>
-          </span>
-        </div>
-      );
-    }
-    return <></>;
-}

+ 1 - 4
packages/editor/src/services/index.ts

@@ -1,4 +1 @@
-export * from './codemirror-editor';
-export * from './file-dropzone';
-export * from './editor-theme';
-export * from './keymaps';
+export * from './use-codemirror-editor';

+ 1 - 0
packages/editor/src/services/use-codemirror-editor/index.ts

@@ -0,0 +1 @@
+export * from './use-codemirror-editor';

+ 4 - 3
packages/editor/src/services/codemirror-editor/use-codemirror-editor/use-codemirror-editor.ts → packages/editor/src/services/use-codemirror-editor/use-codemirror-editor.ts

@@ -1,15 +1,16 @@
 import { useMemo } from 'react';
 
-import {
+import type {
   EditorState,
 } from '@codemirror/state';
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@codemirror/view';
 import { useCodeMirror, type UseCodeMirror } from '@uiw/react-codemirror';
 import deepmerge from 'ts-deepmerge';
 
 import { useAppendExtensions, type AppendExtensions } from './utils/append-extensions';
 import { useFocus, type Focus } from './utils/focus';
-import { FoldDrawio, useFoldDrawio } from './utils/fold-drawio';
+import type { FoldDrawio } from './utils/fold-drawio';
+import { useFoldDrawio } from './utils/fold-drawio';
 import { useGetDoc, type GetDoc } from './utils/get-doc';
 import { useInitDoc, type InitDoc } from './utils/init-doc';
 import { useInsertMarkdownElements, type InsertMarkdowElements } from './utils/insert-markdown-elements';

+ 3 - 2
packages/editor/src/services/codemirror-editor/use-codemirror-editor/utils/append-extensions.ts → packages/editor/src/services/use-codemirror-editor/utils/append-extensions.ts

@@ -1,7 +1,8 @@
 import { useCallback } from 'react';
 
-import { Compartment, Extension, StateEffect } from '@codemirror/state';
-import { EditorView } from '@codemirror/view';
+import type { Extension } from '@codemirror/state';
+import { Compartment, StateEffect } from '@codemirror/state';
+import type { EditorView } from '@codemirror/view';
 
 type CleanupFunctions = () => void;
 export type AppendExtensions = (extensions: Extension | Extension[]) => CleanupFunctions | undefined;

+ 1 - 1
packages/editor/src/services/codemirror-editor/use-codemirror-editor/utils/focus.ts → packages/editor/src/services/use-codemirror-editor/utils/focus.ts

@@ -1,6 +1,6 @@
 import { useCallback } from 'react';
 
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@codemirror/view';
 
 export type Focus = () => void;
 

+ 1 - 1
packages/editor/src/services/codemirror-editor/use-codemirror-editor/utils/fold-drawio.ts → packages/editor/src/services/use-codemirror-editor/utils/fold-drawio.ts

@@ -1,7 +1,7 @@
 import { useEffect } from 'react';
 
 import { foldEffect } from '@codemirror/language';
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@codemirror/view';
 
 export type FoldDrawio = void;
 

+ 1 - 1
packages/editor/src/services/codemirror-editor/use-codemirror-editor/utils/get-doc.ts → packages/editor/src/services/use-codemirror-editor/utils/get-doc.ts

@@ -1,6 +1,6 @@
 import { useCallback } from 'react';
 
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@codemirror/view';
 
 export type GetDoc = () => string;
 

+ 1 - 1
packages/editor/src/services/codemirror-editor/use-codemirror-editor/utils/init-doc.ts → packages/editor/src/services/use-codemirror-editor/utils/init-doc.ts

@@ -1,7 +1,7 @@
 import { useCallback } from 'react';
 
 import { Transaction } from '@codemirror/state';
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@codemirror/view';
 
 export type InitDoc = (doc?: string) => void;
 

+ 1 - 1
packages/editor/src/services/codemirror-editor/use-codemirror-editor/utils/insert-markdown-elements.ts → packages/editor/src/services/use-codemirror-editor/utils/insert-markdown-elements.ts

@@ -1,6 +1,6 @@
 import { useCallback } from 'react';
 
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@codemirror/view';
 
 export type InsertMarkdowElements = (
   prefix: string,

+ 3 - 2
packages/editor/src/services/codemirror-editor/use-codemirror-editor/utils/insert-prefix.ts → packages/editor/src/services/use-codemirror-editor/utils/insert-prefix.ts

@@ -1,6 +1,7 @@
 import { useCallback } from 'react';
 
-import { EditorView } from '@codemirror/view';
+import type { ChangeSpec } from '@codemirror/state';
+import type { EditorView } from '@codemirror/view';
 
 export type InsertPrefix = (prefix: string, noSpaceIfPrefixExists?: boolean) => void;
 
@@ -16,7 +17,7 @@ export const useInsertPrefix = (view?: EditorView): InsertPrefix => {
     const endLine = view.state.doc.lineAt(to);
 
     // Insert prefix for each line
-    const lines = [];
+    const lines: ChangeSpec[] = [];
     let insertTextLength = 0;
     for (let i = startLine.number; i <= endLine.number; i++) {
       const line = view.state.doc.line(i);

+ 1 - 1
packages/editor/src/services/codemirror-editor/use-codemirror-editor/utils/insert-text.ts → packages/editor/src/services/use-codemirror-editor/utils/insert-text.ts

@@ -1,6 +1,6 @@
 import { useCallback } from 'react';
 
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@codemirror/view';
 
 export type InsertText = (text: string) => void;
 

+ 1 - 1
packages/editor/src/services/codemirror-editor/use-codemirror-editor/utils/replace-text.ts → packages/editor/src/services/use-codemirror-editor/utils/replace-text.ts

@@ -1,6 +1,6 @@
 import { useCallback } from 'react';
 
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@codemirror/view';
 
 export type ReplaceText = (text: string) => void;
 

+ 1 - 1
packages/editor/src/services/codemirror-editor/use-codemirror-editor/utils/set-caret-line.ts → packages/editor/src/services/use-codemirror-editor/utils/set-caret-line.ts

@@ -1,6 +1,6 @@
 import { useCallback } from 'react';
 
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@codemirror/view';
 
 export type SetCaretLine = (lineNumber?: number) => void;
 

+ 1 - 2
packages/editor/src/stores/codemirror-editor.ts

@@ -5,8 +5,7 @@ import type { ReactCodeMirrorProps, UseCodeMirror } from '@uiw/react-codemirror'
 import type { SWRResponse } from 'swr';
 import deepmerge from 'ts-deepmerge';
 
-import type { UseCodeMirrorEditor } from '../services';
-import { useCodeMirrorEditor } from '../services';
+import { type UseCodeMirrorEditor, useCodeMirrorEditor } from '../services';
 
 
 const isValid = (u: UseCodeMirrorEditor) => {

+ 1 - 1
packages/editor/src/stores/use-collaborative-editor-mode.ts

@@ -8,7 +8,7 @@ import { SocketIOProvider } from 'y-socket.io';
 import * as Y from 'yjs';
 
 import { userColor } from '../consts';
-import { UseCodeMirrorEditor } from '../services';
+import type { UseCodeMirrorEditor } from '../services';
 
 type UserLocalState = {
   name: string;

+ 3 - 2
packages/editor/src/stores/use-default-extensions.ts

@@ -7,11 +7,12 @@ import { languages } from '@codemirror/language-data';
 import {
   Prec, type Extension,
 } from '@codemirror/state';
-import { keymap, EditorView, KeyBinding } from '@codemirror/view';
+import type { KeyBinding } from '@codemirror/view';
+import { keymap, EditorView } from '@codemirror/view';
 import { tags } from '@lezer/highlight';
 
 import type { UseCodeMirrorEditor } from '../services';
-import { emojiAutocompletionSettings } from '../services/extensions/emojiAutocompletionSettings';
+import { emojiAutocompletionSettings } from '../services-internal';
 
 
 // set new markdownKeymap instead of default one

+ 8 - 6
packages/editor/src/stores/use-editor-settings.ts

@@ -1,15 +1,17 @@
 import { useEffect, useCallback, useState } from 'react';
 
-import { Prec, Extension } from '@codemirror/state';
+import type { Extension } from '@codemirror/state';
+import { Prec } from '@codemirror/state';
 import {
   keymap, type Command, highlightActiveLine, highlightActiveLineGutter,
 } from '@codemirror/view';
 
-import type { EditorSettings } from '../consts';
-import type { UseCodeMirrorEditor, EditorTheme, KeyMapMode } from '../services';
-import { getEditorTheme, getKeymap } from '../services';
-import { insertNewlineContinueMarkup } from '../services/list-util/insert-newline-continue-markup';
-import { insertNewRowToMarkdownTable, isInTable } from '../services/table-util/insert-new-row-to-table-markdown';
+import type { EditorSettings, KeyMapMode, EditorTheme } from '../consts';
+import type { UseCodeMirrorEditor } from '../services';
+import {
+  getEditorTheme, getKeymap, insertNewlineContinueMarkup, insertNewRowToMarkdownTable, isInTable,
+} from '../services-internal';
+
 
 export const useEditorSettings = (
     codeMirrorEditor?: UseCodeMirrorEditor,

+ 1 - 1
packages/editor/src/stores/use-handsontable.ts

@@ -1,6 +1,6 @@
 import { useCallback } from 'react';
 
-import { EditorView } from '@codemirror/view';
+import type { EditorView } from '@codemirror/view';
 import { useSWRStatic } from '@growi/core/dist/swr';
 import type { SWRResponse } from 'swr';
 

+ 2 - 2
packages/editor/src/stores/use-link-edit-modal.ts

@@ -1,7 +1,7 @@
 import { useSWRStatic } from '@growi/core/dist/swr';
-import { SWRResponse } from 'swr';
+import type { SWRResponse } from 'swr';
 
-import Linker from '../services/link-util/Linker';
+import type { Linker } from '../services-internal';
 
 type LinkEditModalStatus = {
   isOpened: boolean,

+ 1 - 1
packages/editor/src/stores/use-resolved-theme.ts

@@ -1,6 +1,6 @@
 import { useCallback } from 'react';
 
-import { ColorScheme } from '@growi/core';
+import type { ColorScheme } from '@growi/core';
 import { useSWRStatic } from '@growi/core/dist/swr';
 import type { SWRResponse } from 'swr';
 import { mutate } from 'swr';

+ 1 - 0
packages/editor/svg/table.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="203" height="160" viewBox="0 0 20.3 16"><path d="M19.1 16H1.2A1.2 1.2 0 0 1 0 14.8V1.2A1.2 1.2 0 0 1 1.2 0h17.9a1.2 1.2 0 0 1 1.2 1.2v13.6a1.2 1.2 0 0 1-1.2 1.2zm-5.2-4.3v3.2h5.3v-3.2zm-6.4 0v3.2h5.3v-3.2zm-6.4 0v3.2h5.3v-3.2zm12.8-4.2v3.2h5.3V7.5zm-6.4 0v3.2h5.3V7.5zm-6.4 0v3.2h5.3V7.5zm12.8-4.3v3.2h5.3V3.2zm-6.4 0v3.2h5.3V3.2zm-6.4 0v3.2h5.3V3.2z"/></svg>

+ 1 - 1
packages/pluginkit/package.json

@@ -21,7 +21,7 @@
     "test": "vitest run --coverage"
   },
   "dependencies": {
-    "@growi/core": "link:../core",
+    "@growi/core": "^0.9.0",
     "extensible-custom-error": "^0.0.7"
   },
   "devDependencies": {

File diff suppressed because it is too large
+ 579 - 102
yarn.lock


Some files were not shown because too many files changed in this diff