This is an automated email from the ASF dual-hosted git repository. robin0716 pushed a commit to branch feat/1.7.2/ui in repository https://gitbox.apache.org/repos/asf/answer.git
commit aa7e19b89675a75124d0d3141b8524909802eff0 Author: robin <[email protected]> AuthorDate: Mon Dec 22 18:25:42 2025 +0800 Remove TipTap editor utility files including commands, constants, error handling, events, position conversion, and table extension to streamline the editor's functionality and reduce code complexity. --- ui/package.json | 9 +- ui/pnpm-lock.yaml | 671 +------------------ ui/src/components/Editor/RichEditor.tsx | 206 ------ ui/src/components/Editor/index.tsx | 40 +- ui/src/components/Editor/utils/tiptap/adapter.ts | 59 -- ui/src/components/Editor/utils/tiptap/base.ts | 358 ---------- ui/src/components/Editor/utils/tiptap/commands.ts | 720 --------------------- ui/src/components/Editor/utils/tiptap/constants.ts | 48 -- .../components/Editor/utils/tiptap/errorHandler.ts | 155 ----- ui/src/components/Editor/utils/tiptap/events.ts | 104 --- ui/src/components/Editor/utils/tiptap/position.ts | 147 ----- .../Editor/utils/tiptap/tableExtension.ts | 81 --- 12 files changed, 5 insertions(+), 2593 deletions(-) diff --git a/ui/package.json b/ui/package.json index 005a6aba..b88fc12d 100644 --- a/ui/package.json +++ b/ui/package.json @@ -21,13 +21,6 @@ "@codemirror/language-data": "^6.5.0", "@codemirror/state": "^6.5.0", "@codemirror/view": "^6.26.1", - "@tiptap/core": "^3.13.0", - "@tiptap/extension-image": "^3.13.0", - "@tiptap/extension-placeholder": "^3.13.0", - "@tiptap/extension-table": "^3.13.0", - "@tiptap/markdown": "^3.13.0", - "@tiptap/react": "^3.13.0", - "@tiptap/starter-kit": "^3.13.0", "axios": "^1.7.7", "bootstrap": "^5.3.2", "bootstrap-icons": "^1.10.5", @@ -107,4 +100,4 @@ "pnpm": ">=9" }, "license": "MIT" -} \ No newline at end of file +} diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index 3fa75e7b..89a37ab1 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -20,27 +20,6 @@ importers: '@codemirror/view': specifier: ^6.26.1 version: 6.35.3 - '@tiptap/core': - specifier: ^3.13.0 - version: 3.13.0(@tiptap/[email protected]) - '@tiptap/extension-image': - specifier: ^3.13.0 - version: 3.13.0(@tiptap/[email protected](@tiptap/[email protected])) - '@tiptap/extension-placeholder': - specifier: ^3.13.0 - version: 3.13.0(@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])) - '@tiptap/extension-table': - specifier: ^3.13.0 - version: 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - '@tiptap/markdown': - specifier: ^3.13.0 - version: 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - '@tiptap/react': - specifier: ^3.13.0 - version: 3.13.0(@floating-ui/[email protected])(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected]([email protected]))([email protected]) - '@tiptap/starter-kit': - specifier: ^3.13.0 - version: 3.13.0 axios: specifier: ^1.7.7 version: 1.7.9 @@ -1245,15 +1224,6 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@floating-ui/[email protected]': - resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} - - '@floating-ui/[email protected]': - resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} - - '@floating-ui/[email protected]': - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - '@fullhuman/[email protected]': resolution: {integrity: sha512-jqcsyfvq09VOsMXxJMPLRF6Fhg/NNltzWKnC9qtzva+QKTxerCO4esG6je7hbnmkpZtaDyPTwMBj9bzfWorsrw==} peerDependencies: @@ -1497,9 +1467,6 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@remirror/[email protected]': - resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} - '@restart/[email protected]': resolution: {integrity: sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==} peerDependencies: @@ -1717,177 +1684,6 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' - '@tiptap/[email protected]': - resolution: {integrity: sha512-iUelgiTMgPVMpY5ZqASUpk8mC8HuR9FWKaDzK27w9oWip9tuB54Z8mePTxNcQaSPb6ErzEaC8x8egrRt7OsdGQ==} - peerDependencies: - '@tiptap/pm': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-K1z/PAIIwEmiWbzrP//4cC7iG1TZknDlF1yb42G7qkx2S2X4P0NiqX7sKOej3yqrPjKjGwPujLMSuDnCF87QkQ==} - peerDependencies: - '@tiptap/core': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-VYiDN9EEwR6ShaDLclG8mphkb/wlIzqfk7hxaKboq1G+NSDj8PcaSI9hldKKtTCLeaSNu6UR5nkdu/YHdzYWTw==} - peerDependencies: - '@tiptap/core': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-qZ3j2DBsqP9DjG2UlExQ+tHMRhAnWlCKNreKddKocb/nAFrPdBCtvkqIEu+68zPlbLD4ukpoyjUklRJg+NipFg==} - peerDependencies: - '@tiptap/core': ^3.13.0 - '@tiptap/pm': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-fFQmmEUoPzRGiQJ/KKutG35ZX21GE+1UCDo8Q6PoWH7Al9lex47nvyeU1BiDYOhcTKgIaJRtEH5lInsOsRJcSA==} - peerDependencies: - '@tiptap/extension-list': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-kIwfQ4iqootsWg9e74iYJK54/YMIj6ahUxEltjZRML5z/h4gTDcQt2eTpnEC8yjDjHeUVOR94zH9auCySyk9CQ==} - peerDependencies: - '@tiptap/core': ^3.13.0 - '@tiptap/pm': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-sF5raBni6iSVpXWvwJCAcOXw5/kZ+djDHx1YSGWhopm4+fsj0xW7GvVO+VTwiFjZGKSw+K5NeAxzcQTJZd3Vhw==} - peerDependencies: - '@tiptap/core': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-RjU7hTJwjKXIdY57o/Pc+Yr8swLkrwT7PBQ/m+LCX5oO/V2wYoWCjoBYnK5KSHrWlNy/aLzC33BvLeqZZ9nzlQ==} - peerDependencies: - '@tiptap/core': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-m7GPT3c/83ni+bbU8c+3dpNa8ug+aQ4phNB1Q52VQG3oTonDJnZS7WCtn3lB/Hi1LqoqMtEHwhepU2eD+JeXqQ==} - peerDependencies: - '@tiptap/extensions': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-OsezV2cMofZM4c13gvgi93IEYBUzZgnu8BXTYZQiQYekz4bX4uulBmLa1KOA9EN71FzS+SoLkXHU0YzlbLjlxA==} - peerDependencies: - '@floating-ui/dom': ^1.0.0 - '@tiptap/core': ^3.13.0 - '@tiptap/pm': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-KVxjQKkd964nin+1IdM2Dvej/Jy4JTMcMgq5seusUhJ9T9P8F9s2D5Iefwgkps3OCzub/aF+eAsZe+1P5KSIgA==} - peerDependencies: - '@tiptap/extensions': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-nH1OBaO+/pakhu+P1jF208mPgB70IKlrR/9d46RMYoYbqJTNf4KVLx5lHAOHytIhjcNg+MjyTfJWfkK+dyCCyg==} - peerDependencies: - '@tiptap/core': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-8VKWX8waYPtUWN97J89em9fOtxNteh6pvUEd0htcOAtoxjt2uZjbW5N4lKyWhNKifZBrVhH2Cc2NUPuftCVgxw==} - peerDependencies: - '@tiptap/core': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-ZUFyORtjj22ib8ykbxRhWFQOTZjNKqOsMQjaAGof30cuD2DN5J5pMz7Haj2fFRtLpugWYH+f0Mi+WumQXC3hCw==} - peerDependencies: - '@tiptap/core': ^3.13.0 - '@tiptap/pm': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-223uzLUkIa1rkK7aQK3AcIXe6LbCtmnpVb7sY5OEp+LpSaSPyXwyrZ4A0EO1o98qXG68/0B2OqMntFtA9c5Fbw==} - peerDependencies: - '@tiptap/core': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-XbVTgmzk1kgUMTirA6AGdLTcKHUvEJoh3R4qMdPtwwygEOe7sBuvKuLtF6AwUtpnOM+Y3tfWUTNEDWv9AcEdww==} - peerDependencies: - '@tiptap/core': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-LuFPJ5GoL12GHW4A+USsj60O90pLcwUPdvEUSWewl9USyG6gnLnY/j5ZOXPYH7LiwYW8+lhq7ABwrDF2PKyBbA==} - peerDependencies: - '@tiptap/core': ^3.13.0 - '@tiptap/pm': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-63NbcS/XeQP2jcdDEnEAE3rjJICDj8y1SN1h/MsJmSt1LusnEo8WQ2ub86QELO6XnD3M04V03cY6Knf6I5mTkw==} - peerDependencies: - '@tiptap/extension-list': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-P+HtIa1iwosb1feFc8B/9MN5EAwzS+/dZ0UH0CTF2E4wnp5Z9OMxKl1IYjfiCwHzZrU5Let+S/maOvJR/EmV0g==} - peerDependencies: - '@tiptap/extension-list': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-MMFH0jQ4LeCPkJJFyZ77kt6eM/vcKujvTbMzW1xSHCIEA6s4lEcx9QdZMPpfmnOvTzeoVKR4nsu2t2qT9ZXzAw==} - peerDependencies: - '@tiptap/core': ^3.13.0 - '@tiptap/pm': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-QuDyLzuK/3vCvx9GeKhgvHWrGECBzmJyAx6gli2HY+Iil7XicbfltV4nvhIxgxzpx3LDHLKzJN9pBi+2MzX60g==} - peerDependencies: - '@tiptap/extension-list': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-9csQde1i0yeZI5oQQ9e1GYNtGL2JcC2d8Fwtw9FsGC8yz2W0h+Fmk+3bc2kobbtO5LGqupSc1fKM8fAg5rSRDg==} - peerDependencies: - '@tiptap/core': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-Au4ktRBraQktX9gjSzGWyJV6kPof7+kOhzE8ej+rOMjIrHbx3DCHy1CJWftSO9BbqIyonjsFmm4nE+vjzZ3Z5Q==} - peerDependencies: - '@tiptap/extensions': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-VHhWNqTAMOfrC48m2FcPIZB0nhl6XHQviAV16SBc+EFznKNv9tQUsqQrnuQ2y6ZVfqq5UxvZ3hKF/JlN/Ff7xw==} - peerDependencies: - '@tiptap/core': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-LcH9KE4QBUJ6IPwt1Uo5iU7zatFjUUvXbctIu2fKQ9nqJ7nNSFxRhkNyporVFkTWYH7/rb0qMoF1VxSUGefG5w==} - peerDependencies: - '@tiptap/core': ^3.13.0 - '@tiptap/pm': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-VcZIna93rixw7hRkHGCxDbL3kvJWi80vIT25a2pXg0WP1e7Pi3nBYvZIL4SQtkbBCji9EHrbZx3p8nNPzfazYw==} - peerDependencies: - '@tiptap/core': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-VDQi+UYw0tFnfghpthJTFmtJ3yx90kXeDwFvhmT8G+O+si5VmP05xYDBYBmYCix5jqKigJxEASiBL0gYOgMDEg==} - peerDependencies: - '@tiptap/core': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-i7O0ptSibEtTy+2PIPsNKEvhTvMaFJg1W4Oxfnbuxvaigs7cJV9Q0lwDUcc7CPsNw2T1+44wcxg431CzTvdYoA==} - peerDependencies: - '@tiptap/core': ^3.13.0 - '@tiptap/pm': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-BI1GZxDFBrEeYbngbKh/si48tRSXO6HVGg7KzlfOwdncSD982/loG2KUnFIjoVGjmMzXNDWbI6O/eqfLVQPB5Q==} - peerDependencies: - '@tiptap/core': ^3.13.0 - '@tiptap/pm': ^3.13.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-WKR4ucALq+lwx0WJZW17CspeTpXorbIOpvKv5mulZica6QxqfMhn8n1IXCkDws/mCoLRx4Drk5d377tIjFNsvQ==} - - '@tiptap/[email protected]': - resolution: {integrity: sha512-VqpqNZ9qtPr3pWK4NsZYxXgLSEiAnzl6oS7tEGmkkvJbcGSC+F7R13Xc9twv/zT5QCLxaHdEbmxHbuAIkrMgJQ==} - peerDependencies: - '@tiptap/core': ^3.13.0 - '@tiptap/pm': ^3.13.0 - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - '@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - - '@tiptap/[email protected]': - resolution: {integrity: sha512-Ojn6sRub04CRuyQ+9wqN62JUOMv+rG1vXhc2s6DCBCpu28lkCMMW+vTe7kXJcEdbot82+5swPbERw9vohswFzg==} - '@tootallnate/[email protected]': resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} engines: {node: '>= 6'} @@ -2007,21 +1803,12 @@ packages: '@types/[email protected]': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/[email protected]': - resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} - '@types/[email protected]': resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} - '@types/[email protected]': - resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} - '@types/[email protected]': resolution: {integrity: sha512-a79Yc3TOk6dGdituy8hmTTJXjOkZ7zsFYV10L337ttq/rec8lRMDBpV7fL3uLx6TgbFCa5DU/h8FmIBQPSbU0w==} - '@types/[email protected]': - resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} - '@types/[email protected]': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} @@ -2096,9 +1883,6 @@ packages: '@types/[email protected]': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@types/[email protected]': - resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} - '@types/[email protected]': resolution: {integrity: sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==} @@ -3380,10 +3164,6 @@ packages: [email protected]: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} - [email protected]: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - [email protected]: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} @@ -3747,10 +3527,6 @@ packages: [email protected]: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - [email protected]: - resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} - engines: {node: '>=6.0.0'} - [email protected]: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -4775,12 +4551,6 @@ packages: [email protected]: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - [email protected]: - resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} - - [email protected]: - resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==} - [email protected]: resolution: {integrity: sha512-WyCzSbfYGhK7cU+UuDDkzUiytbfbi0ZdPy2orwtM75P3WTtQBzmG40cCxIa8Ii2+XjfxzLH6Be46tUfWS85Xfg==} engines: {node: '>=18.12.0'} @@ -4909,15 +4679,6 @@ packages: resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} engines: {node: '>=8'} - [email protected]: - resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} - hasBin: true - - [email protected]: - resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==} - engines: {node: '>= 18'} - hasBin: true - [email protected]: resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} engines: {node: '>= 12'} @@ -4929,9 +4690,6 @@ packages: [email protected]: resolution: {integrity: sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==} - [email protected]: - resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - [email protected]: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -5210,9 +4968,6 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - [email protected]: - resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} - [email protected]: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -5825,64 +5580,6 @@ packages: [email protected]: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - [email protected]: - resolution: {integrity: sha512-j0kORIBm8ayJNl3zQvD1TTPHJX3g042et6y/KQhZhnPrruO8exkTgG8X+NRpj7kIyMMEx74Xb3DyMIBtO0IKkQ==} - - [email protected]: - resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} - - [email protected]: - resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==} - - [email protected]: - resolution: {integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==} - - [email protected]: - resolution: {integrity: sha512-z00qvurSdCEWUIulij/isHaqu4uLS8r/Fi61IbjdIPJEonQgggbJsLnstW7Lgdk4zQ68/yr6B6bf7sJXowIgdQ==} - - [email protected]: - resolution: {integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==} - - [email protected]: - resolution: {integrity: sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==} - - [email protected]: - resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} - - [email protected]: - resolution: {integrity: sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==} - - [email protected]: - resolution: {integrity: sha512-qwXzynnpBIeg1D7BAtjOusR+81xCp53j7iWu/IargiRZqRjGIlQuu1f3jFi+ehrHhWMLoyOQTSRx/IWZJqOYtQ==} - - [email protected]: - resolution: {integrity: sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==} - - [email protected]: - resolution: {integrity: sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==} - - [email protected]: - resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} - - [email protected]: - resolution: {integrity: sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==} - - [email protected]: - resolution: {integrity: sha512-DAgDoUYHCcc6tOGpLVPSU1k84kCUWTWnfWX3UDy2Delv4ryH0KqTD6RBI6k4yi9j9I8gl3j8MkPpRD/vWPZbug==} - - [email protected]: - resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==} - peerDependencies: - prosemirror-model: ^1.22.1 - prosemirror-state: ^1.4.2 - prosemirror-view: ^1.33.8 - - [email protected]: - resolution: {integrity: sha512-RPDQCxIDhIBb1o36xxwsaeAvivO8VLJcgBtzmOwQ64bMtsVFh5SSuJ6dWSxO1UsHTiTXPCgQm3PDJt7p6IOLbw==} - - [email protected]: - resolution: {integrity: sha512-SqMiYMUQNNBP9kfPhLO8WXEk/fon47vc52FQsUiJzTBuyjKgEcoAwMyF04eQ4WZ2ArMn7+ReypYL60aKngbACQ==} - [email protected]: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -5893,10 +5590,6 @@ packages: [email protected]: resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} - [email protected]: - resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} - engines: {node: '>=6'} - [email protected]: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -6242,9 +5935,6 @@ packages: engines: {node: '>=10.0.0'} hasBin: true - [email protected]: - resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} - [email protected]: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -6911,9 +6601,6 @@ packages: engines: {node: '>=4.2.0'} hasBin: true - [email protected]: - resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - [email protected]: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} @@ -8729,20 +8416,6 @@ snapshots: '@eslint/[email protected]': {} - '@floating-ui/[email protected]': - dependencies: - '@floating-ui/utils': 0.2.10 - optional: true - - '@floating-ui/[email protected]': - dependencies: - '@floating-ui/core': 1.7.3 - '@floating-ui/utils': 0.2.10 - optional: true - - '@floating-ui/[email protected]': - optional: true - '@fullhuman/[email protected]([email protected])': dependencies: postcss: 8.4.49 @@ -9129,8 +8802,6 @@ snapshots: '@swc/helpers': 0.5.15 react: 18.3.1 - '@remirror/[email protected]': {} - '@restart/[email protected]([email protected])': dependencies: dequal: 2.0.3 @@ -9374,202 +9045,6 @@ snapshots: '@babel/runtime': 7.26.0 '@testing-library/dom': 8.20.1 - '@tiptap/[email protected](@tiptap/[email protected])': - dependencies: - '@tiptap/pm': 3.13.0 - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])': - dependencies: - '@floating-ui/dom': 1.7.4 - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - '@tiptap/pm': 3.13.0 - optional: true - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]))': - dependencies: - '@tiptap/extension-list': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - '@tiptap/pm': 3.13.0 - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]))': - dependencies: - '@tiptap/extensions': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - - '@tiptap/[email protected](@floating-ui/[email protected])(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])': - dependencies: - '@floating-ui/dom': 1.7.4 - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - '@tiptap/pm': 3.13.0 - optional: true - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]))': - dependencies: - '@tiptap/extensions': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - '@tiptap/pm': 3.13.0 - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - '@tiptap/pm': 3.13.0 - linkifyjs: 4.3.2 - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]))': - dependencies: - '@tiptap/extension-list': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]))': - dependencies: - '@tiptap/extension-list': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - '@tiptap/pm': 3.13.0 - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]))': - dependencies: - '@tiptap/extension-list': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]))': - dependencies: - '@tiptap/extensions': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - '@tiptap/pm': 3.13.0 - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - '@tiptap/pm': 3.13.0 - - '@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - '@tiptap/pm': 3.13.0 - marked: 15.0.12 - - '@tiptap/[email protected]': - dependencies: - prosemirror-changeset: 2.3.1 - prosemirror-collab: 1.3.1 - prosemirror-commands: 1.7.1 - prosemirror-dropcursor: 1.8.2 - prosemirror-gapcursor: 1.4.0 - prosemirror-history: 1.5.0 - prosemirror-inputrules: 1.5.1 - prosemirror-keymap: 1.2.3 - prosemirror-markdown: 1.13.2 - prosemirror-menu: 1.2.5 - prosemirror-model: 1.25.4 - prosemirror-schema-basic: 1.2.4 - prosemirror-schema-list: 1.5.1 - prosemirror-state: 1.4.4 - prosemirror-tables: 1.8.1 - prosemirror-trailing-node: 3.0.0([email protected])([email protected])([email protected]) - prosemirror-transform: 1.10.5 - prosemirror-view: 1.41.3 - - '@tiptap/[email protected](@floating-ui/[email protected])(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected]([email protected]))([email protected])': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - '@tiptap/pm': 3.13.0 - '@types/react': 18.3.16 - '@types/react-dom': 18.3.5(@types/[email protected]) - '@types/use-sync-external-store': 0.0.6 - fast-equals: 5.4.0 - react: 18.3.1 - react-dom: 18.3.1([email protected]) - use-sync-external-store: 1.6.0([email protected]) - optionalDependencies: - '@tiptap/extension-bubble-menu': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - '@tiptap/extension-floating-menu': 3.13.0(@floating-ui/[email protected])(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - transitivePeerDependencies: - - '@floating-ui/dom' - - '@tiptap/[email protected]': - dependencies: - '@tiptap/core': 3.13.0(@tiptap/[email protected]) - '@tiptap/extension-blockquote': 3.13.0(@tiptap/[email protected](@tiptap/[email protected])) - '@tiptap/extension-bold': 3.13.0(@tiptap/[email protected](@tiptap/[email protected])) - '@tiptap/extension-bullet-list': 3.13.0(@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])) - '@tiptap/extension-code': 3.13.0(@tiptap/[email protected](@tiptap/[email protected])) - '@tiptap/extension-code-block': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - '@tiptap/extension-document': 3.13.0(@tiptap/[email protected](@tiptap/[email protected])) - '@tiptap/extension-dropcursor': 3.13.0(@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])) - '@tiptap/extension-gapcursor': 3.13.0(@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])) - '@tiptap/extension-hard-break': 3.13.0(@tiptap/[email protected](@tiptap/[email protected])) - '@tiptap/extension-heading': 3.13.0(@tiptap/[email protected](@tiptap/[email protected])) - '@tiptap/extension-horizontal-rule': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - '@tiptap/extension-italic': 3.13.0(@tiptap/[email protected](@tiptap/[email protected])) - '@tiptap/extension-link': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - '@tiptap/extension-list': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - '@tiptap/extension-list-item': 3.13.0(@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])) - '@tiptap/extension-list-keymap': 3.13.0(@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])) - '@tiptap/extension-ordered-list': 3.13.0(@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected])) - '@tiptap/extension-paragraph': 3.13.0(@tiptap/[email protected](@tiptap/[email protected])) - '@tiptap/extension-strike': 3.13.0(@tiptap/[email protected](@tiptap/[email protected])) - '@tiptap/extension-text': 3.13.0(@tiptap/[email protected](@tiptap/[email protected])) - '@tiptap/extension-underline': 3.13.0(@tiptap/[email protected](@tiptap/[email protected])) - '@tiptap/extensions': 3.13.0(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]) - '@tiptap/pm': 3.13.0 - '@tootallnate/[email protected]': {} '@trysound/[email protected]': {} @@ -9715,19 +9190,10 @@ snapshots: '@types/[email protected]': {} - '@types/[email protected]': {} - '@types/[email protected]': {} - '@types/[email protected]': - dependencies: - '@types/linkify-it': 5.0.0 - '@types/mdurl': 2.0.0 - '@types/[email protected]': {} - '@types/[email protected]': {} - '@types/[email protected]': {} '@types/[email protected]': {} @@ -9798,8 +9264,6 @@ snapshots: '@types/[email protected]': {} - '@types/[email protected]': {} - '@types/[email protected]': {} '@types/[email protected]': @@ -11233,8 +10697,6 @@ snapshots: [email protected]: {} - [email protected]: {} - [email protected]: {} [email protected]: @@ -11831,8 +11293,6 @@ snapshots: [email protected]: {} - [email protected]: {} - [email protected]: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -13126,12 +12586,6 @@ snapshots: [email protected]: {} - [email protected]: - dependencies: - uc.micro: 2.1.0 - - [email protected]: {} - [email protected]: dependencies: chalk: 5.4.1 @@ -13259,25 +12713,12 @@ snapshots: [email protected]: {} - [email protected]: - dependencies: - argparse: 2.0.1 - entities: 4.5.0 - linkify-it: 5.0.0 - mdurl: 2.0.0 - punycode.js: 2.3.1 - uc.micro: 2.1.0 - - [email protected]: {} - [email protected]: {} [email protected]: {} [email protected]: {} - [email protected]: {} - [email protected]: {} [email protected]: @@ -13558,8 +12999,6 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - [email protected]: {} - [email protected]: dependencies: p-try: 2.2.0 @@ -14151,109 +13590,6 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 - [email protected]: - dependencies: - prosemirror-transform: 1.10.5 - - [email protected]: - dependencies: - prosemirror-state: 1.4.4 - - [email protected]: - dependencies: - prosemirror-model: 1.25.4 - prosemirror-state: 1.4.4 - prosemirror-transform: 1.10.5 - - [email protected]: - dependencies: - prosemirror-state: 1.4.4 - prosemirror-transform: 1.10.5 - prosemirror-view: 1.41.3 - - [email protected]: - dependencies: - prosemirror-keymap: 1.2.3 - prosemirror-model: 1.25.4 - prosemirror-state: 1.4.4 - prosemirror-view: 1.41.3 - - [email protected]: - dependencies: - prosemirror-state: 1.4.4 - prosemirror-transform: 1.10.5 - prosemirror-view: 1.41.3 - rope-sequence: 1.3.4 - - [email protected]: - dependencies: - prosemirror-state: 1.4.4 - prosemirror-transform: 1.10.5 - - [email protected]: - dependencies: - prosemirror-state: 1.4.4 - w3c-keyname: 2.2.8 - - [email protected]: - dependencies: - '@types/markdown-it': 14.1.2 - markdown-it: 14.1.0 - prosemirror-model: 1.25.4 - - [email protected]: - dependencies: - crelt: 1.0.6 - prosemirror-commands: 1.7.1 - prosemirror-history: 1.5.0 - prosemirror-state: 1.4.4 - - [email protected]: - dependencies: - orderedmap: 2.1.1 - - [email protected]: - dependencies: - prosemirror-model: 1.25.4 - - [email protected]: - dependencies: - prosemirror-model: 1.25.4 - prosemirror-state: 1.4.4 - prosemirror-transform: 1.10.5 - - [email protected]: - dependencies: - prosemirror-model: 1.25.4 - prosemirror-transform: 1.10.5 - prosemirror-view: 1.41.3 - - [email protected]: - dependencies: - prosemirror-keymap: 1.2.3 - prosemirror-model: 1.25.4 - prosemirror-state: 1.4.4 - prosemirror-transform: 1.10.5 - prosemirror-view: 1.41.3 - - [email protected]([email protected])([email protected])([email protected]): - dependencies: - '@remirror/core-constants': 3.0.0 - escape-string-regexp: 4.0.0 - prosemirror-model: 1.25.4 - prosemirror-state: 1.4.4 - prosemirror-view: 1.41.3 - - [email protected]: - dependencies: - prosemirror-model: 1.25.4 - - [email protected]: - dependencies: - prosemirror-model: 1.25.4 - prosemirror-state: 1.4.4 - prosemirror-transform: 1.10.5 - [email protected]: dependencies: forwarded: 0.2.0 @@ -14265,8 +13601,6 @@ snapshots: dependencies: punycode: 2.3.1 - [email protected]: {} - [email protected]: {} [email protected]([email protected](@swc/[email protected])): @@ -14725,8 +14059,6 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - [email protected]: {} - [email protected]: dependencies: queue-microtask: 1.2.3 @@ -15481,8 +14813,6 @@ snapshots: [email protected]: {} - [email protected]: {} - [email protected]: dependencies: call-bind: 1.0.8 @@ -15549,6 +14879,7 @@ snapshots: [email protected]([email protected]): dependencies: react: 18.3.1 + optional: true [email protected]: {} diff --git a/ui/src/components/Editor/RichEditor.tsx b/ui/src/components/Editor/RichEditor.tsx deleted file mode 100644 index 55fca5a9..00000000 --- a/ui/src/components/Editor/RichEditor.tsx +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { useEffect, useRef, useCallback } from 'react'; - -import { - useEditor, - EditorContent, - Editor as TipTapEditor, -} from '@tiptap/react'; -import StarterKit from '@tiptap/starter-kit'; -import Placeholder from '@tiptap/extension-placeholder'; -import { Markdown } from '@tiptap/markdown'; -import Image from '@tiptap/extension-image'; -import { TableRow, TableCell, TableHeader } from '@tiptap/extension-table'; - -import { Editor, BaseEditorProps } from './types'; -import { createTipTapAdapter } from './utils/tiptap/adapter'; -import { TableWithWrapper } from './utils/tiptap/tableExtension'; - -interface RichEditorProps extends BaseEditorProps {} - -const RichEditor: React.FC<RichEditorProps> = ({ - value, - onChange, - onFocus, - onBlur, - placeholder = '', - autoFocus = false, - onEditorReady, -}) => { - const lastSyncedValueRef = useRef<string>(value); - const adaptedEditorRef = useRef<Editor | null>(null); - const isInitializedRef = useRef<boolean>(false); - const isUpdatingFromPropsRef = useRef<boolean>(false); - const onEditorReadyRef = useRef(onEditorReady); - const autoFocusRef = useRef(autoFocus); - const initialValueRef = useRef<string>(value); - - useEffect(() => { - onEditorReadyRef.current = onEditorReady; - autoFocusRef.current = autoFocus; - }, [onEditorReady, autoFocus]); - - const isViewAvailable = (editorInstance: TipTapEditor | null): boolean => { - if (!editorInstance) { - return false; - } - if (editorInstance.isDestroyed) { - return false; - } - return !!(editorInstance.view && editorInstance.state); - }; - - const handleCreate = useCallback( - ({ editor: editorInstance }: { editor: TipTapEditor }) => { - if (isInitializedRef.current || !isViewAvailable(editorInstance)) { - return; - } - - isInitializedRef.current = true; - - const initialValue = initialValueRef.current; - if (initialValue && initialValue.trim() !== '') { - editorInstance.commands.setContent(initialValue, { - contentType: 'markdown', - }); - lastSyncedValueRef.current = initialValue; - } - - adaptedEditorRef.current = createTipTapAdapter(editorInstance); - onEditorReadyRef.current?.(adaptedEditorRef.current); - - if (autoFocusRef.current) { - editorInstance.commands.focus(); - } - }, - [], - ); - - const handleUpdate = useCallback( - ({ editor: editorInstance }: { editor: TipTapEditor }) => { - if (onChange && !isUpdatingFromPropsRef.current) { - const markdown = editorInstance.getMarkdown(); - onChange(markdown); - lastSyncedValueRef.current = markdown; - } - }, - [onChange], - ); - - const handleFocus = useCallback(() => { - onFocus?.(); - }, [onFocus]); - - const handleBlur = useCallback(() => { - onBlur?.(); - }, [onBlur]); - - const editor = useEditor({ - extensions: [ - StarterKit, - Markdown, - Image, - TableWithWrapper.configure({ - HTMLAttributes: { - class: 'table table-bordered', - style: { - width: '100%', - }, - }, - resizable: true, - wrapperClass: 'table-responsive', - }), - TableRow.configure({ - HTMLAttributes: { - class: 'table-row', - }, - }), - TableCell, - TableHeader, - Placeholder.configure({ - placeholder, - }), - ], - onCreate: handleCreate, - onUpdate: handleUpdate, - onFocus: handleFocus, - onBlur: handleBlur, - editorProps: { - attributes: { - class: 'tiptap-editor fmt', - }, - }, - }); - - useEffect(() => { - if ( - !editor || - !isInitializedRef.current || - !isViewAvailable(editor) || - value === lastSyncedValueRef.current - ) { - return; - } - - try { - const currentMarkdown = editor.getMarkdown(); - if (currentMarkdown !== value) { - isUpdatingFromPropsRef.current = true; - if (value && value.trim() !== '') { - editor.commands.setContent(value, { contentType: 'markdown' }); - } else { - editor.commands.clearContent(); - } - lastSyncedValueRef.current = value || ''; - setTimeout(() => { - isUpdatingFromPropsRef.current = false; - }, 0); - } - } catch (error) { - console.warn('Editor view not available when syncing value:', error); - } - }, [editor, value]); - - useEffect(() => { - initialValueRef.current = value; - lastSyncedValueRef.current = value; - isInitializedRef.current = false; - adaptedEditorRef.current = null; - isUpdatingFromPropsRef.current = false; - - return () => { - if (editor) { - editor.destroy(); - } - isInitializedRef.current = false; - adaptedEditorRef.current = null; - isUpdatingFromPropsRef.current = false; - }; - }, [editor]); - - if (!editor) { - return <div className="editor-loading">Loading editor...</div>; - } - - return <EditorContent className="rich-editor-wrap" editor={editor} />; -}; - -export default RichEditor; diff --git a/ui/src/components/Editor/index.tsx b/ui/src/components/Editor/index.tsx index ebe04876..c6136c3c 100644 --- a/ui/src/components/Editor/index.tsx +++ b/ui/src/components/Editor/index.tsx @@ -51,7 +51,6 @@ import { import { htmlRender } from './utils'; import Viewer from './Viewer'; import { EditorContext } from './EditorContext'; -import RichEditor from './RichEditor'; import MarkdownEditor from './MarkdownEditor'; import { Editor } from './types'; @@ -86,24 +85,11 @@ const MDEditor: ForwardRefRenderFunction<EditorRef, Props> = ( }, ref, ) => { - const [mode, setMode] = useState<'markdown' | 'rich'>('markdown'); const [currentEditor, setCurrentEditor] = useState<Editor | null>(null); const previewRef = useRef<{ getHtml; element } | null>(null); useRenderPlugin(previewRef.current?.element); - const handleModeChange = useCallback( - (newMode: 'markdown' | 'rich') => { - if (newMode === mode) { - return; - } - - setCurrentEditor(null); - setMode(newMode); - }, - [mode], - ); - const getHtml = useCallback(() => { return previewRef.current?.getHtml(); }, []); @@ -116,7 +102,7 @@ const MDEditor: ForwardRefRenderFunction<EditorRef, Props> = ( [getHtml], ); - const EditorComponent = mode === 'markdown' ? MarkdownEditor : RichEditor; + const EditorComponent = MarkdownEditor; return ( <> @@ -149,30 +135,10 @@ const MDEditor: ForwardRefRenderFunction<EditorRef, Props> = ( <Help /> </PluginRender> </EditorContext.Provider> - <div className="btn-group ms-auto" role="group"> - <button - type="button" - className={`btn btn-sm ${ - mode === 'markdown' ? 'btn-primary' : 'btn-outline-secondary' - }`} - title="Markdown Mode" - onClick={() => handleModeChange('markdown')}> - <i className="bi bi-filetype-md" /> - </button> - <button - type="button" - className={`btn btn-sm ${ - mode === 'rich' ? 'btn-primary' : 'btn-outline-secondary' - }`} - title="Rich Mode" - onClick={() => handleModeChange('rich')}> - <i className="bi bi-type" /> - </button> - </div> </div> <EditorComponent - key={mode} + key="markdown-editor" value={value} onChange={(markdown) => { onChange?.(markdown); @@ -186,7 +152,7 @@ const MDEditor: ForwardRefRenderFunction<EditorRef, Props> = ( }} /> </div> - {mode === 'markdown' && <Viewer ref={previewRef} value={value} />} + <Viewer ref={previewRef} value={value} /> </> ); }; diff --git a/ui/src/components/Editor/utils/tiptap/adapter.ts b/ui/src/components/Editor/utils/tiptap/adapter.ts deleted file mode 100644 index 415edb17..00000000 --- a/ui/src/components/Editor/utils/tiptap/adapter.ts +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Editor as TipTapEditor } from '@tiptap/react'; - -import { Editor, ExtendEditor } from '../../types'; - -import { createBaseMethods } from './base'; -import { createEventMethods } from './events'; -import { createCommandMethods } from './commands'; - -/** - * Adapts TipTap editor to CodeMirror editor interface - * - * This adapter function converts TipTap editor's API to a CodeMirror-compatible interface, - * enabling toolbar components to work properly in Rich mode. The adapter implements - * the complete `ExtendEditor` interface, including base methods, event handling, and command methods. - * - * @param editor - TipTap editor instance - * @returns Adapted editor instance that implements the unified Editor interface - * - * @example - * ```typescript - * const tipTapEditor = useEditor({ ... }); - * const adaptedEditor = createTipTapAdapter(tipTapEditor); - * // Now you can use the unified API - * adaptedEditor.insertBold('text'); - * adaptedEditor.insertHeading(1, 'Title'); - * ``` - */ -export function createTipTapAdapter(editor: TipTapEditor): Editor { - const baseMethods = createBaseMethods(editor); - const eventMethods = createEventMethods(editor); - const commandMethods = createCommandMethods(editor); - - const editorAdapter: ExtendEditor = { - ...baseMethods, - ...eventMethods, - ...commandMethods, - }; - - return editorAdapter as unknown as Editor; -} diff --git a/ui/src/components/Editor/utils/tiptap/base.ts b/ui/src/components/Editor/utils/tiptap/base.ts deleted file mode 100644 index e088a9f5..00000000 --- a/ui/src/components/Editor/utils/tiptap/base.ts +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Editor as TipTapEditor } from '@tiptap/react'; - -import { Position } from '../../types'; - -import { - safeExecuteCommand, - EditorErrorType, - handleEditorError, -} from './errorHandler'; -import { - convertTipTapPositionToCodeMirror, - convertCodeMirrorPositionToTipTap, -} from './position'; -import { MARKDOWN_PATTERNS } from './constants'; - -/** - * Creates base methods module - * - * Provides core base methods for the editor, including: - * - Content getter and setter (getValue, setValue) - * - Selection operations (getSelection, replaceSelection) - * - Cursor and selection position (getCursor, setSelection) - * - Read-only state control (setReadOnly) - * - * @param editor - TipTap editor instance - * @returns Object containing base methods - */ -export function createBaseMethods(editor: TipTapEditor) { - return { - getValue: () => { - return ( - safeExecuteCommand( - () => editor.getMarkdown(), - () => '', - EditorErrorType.COMMAND_EXECUTION_FAILED, - { function: 'getValue' }, - ) || '' - ); - }, - - setValue: (value: string) => { - safeExecuteCommand( - () => { - editor.commands.setContent(value, { contentType: 'markdown' }); - }, - undefined, - EditorErrorType.COMMAND_EXECUTION_FAILED, - { function: 'setValue', valueLength: value.length }, - ); - }, - - getSelection: () => { - const { from, to } = editor.state.selection; - return editor.state.doc.textBetween(from, to); - }, - - replaceSelection: (value: string) => { - const inlineCodeMatch = value.match(MARKDOWN_PATTERNS.INLINE_CODE); - if (inlineCodeMatch && value.length > 2) { - const codeText = inlineCodeMatch[1]; - safeExecuteCommand( - () => { - editor.commands.insertContent({ - type: 'text', - text: codeText, - marks: [{ type: 'code' }], - }); - }, - () => { - editor.commands.insertContent(value, { contentType: 'markdown' }); - }, - ); - return; - } - - const codeBlockMatch = value.match(MARKDOWN_PATTERNS.CODE_BLOCK); - if (codeBlockMatch) { - const [, , lang, codeText] = codeBlockMatch; - safeExecuteCommand( - () => { - editor.commands.insertContent({ - type: 'codeBlock', - attrs: lang ? { language: lang } : {}, - content: [ - { - type: 'text', - text: codeText, - }, - ], - }); - }, - () => { - editor.commands.insertContent(value, { contentType: 'markdown' }); - }, - ); - return; - } - - const imageMatch = value.match(MARKDOWN_PATTERNS.IMAGE); - if (imageMatch) { - const [, alt, url] = imageMatch; - safeExecuteCommand( - () => { - editor.commands.insertContent({ - type: 'image', - attrs: { - src: url, - alt: alt || '', - }, - }); - }, - () => { - editor.commands.insertContent(value, { contentType: 'markdown' }); - }, - ); - return; - } - - const linkMatch = value.match(MARKDOWN_PATTERNS.LINK); - if (linkMatch) { - const [, text, url] = linkMatch; - safeExecuteCommand( - () => { - editor.commands.insertContent({ - type: 'text', - text: text || url, - marks: [ - { - type: 'link', - attrs: { - href: url, - }, - }, - ], - }); - }, - () => { - editor.commands.insertContent(value, { contentType: 'markdown' }); - }, - ); - return; - } - - const autoLinkMatch = value.match(MARKDOWN_PATTERNS.AUTO_LINK); - if (autoLinkMatch && value.length > 2) { - const url = autoLinkMatch[1]; - safeExecuteCommand( - () => { - editor.commands.insertContent({ - type: 'text', - text: url, - marks: [ - { - type: 'link', - attrs: { - href: url, - }, - }, - ], - }); - }, - () => { - editor.commands.insertContent(value, { contentType: 'markdown' }); - }, - ); - return; - } - - if (MARKDOWN_PATTERNS.HORIZONTAL_RULE.test(value.trim())) { - safeExecuteCommand( - () => { - editor.commands.insertContent({ - type: 'horizontalRule', - }); - }, - () => { - editor.commands.insertContent(value, { contentType: 'markdown' }); - }, - ); - return; - } - - safeExecuteCommand(() => { - editor.commands.insertContent(value, { contentType: 'markdown' }); - }); - }, - - focus: () => { - editor.commands.focus(); - }, - - getCursor: () => { - try { - const { from } = editor.state.selection; - return convertTipTapPositionToCodeMirror(editor, from); - } catch (error) { - handleEditorError( - error as Error, - EditorErrorType.POSITION_CONVERSION_FAILED, - { - function: 'getCursor', - }, - ); - return { line: 0, ch: 0 }; - } - }, - - setSelection: (anchor?: unknown, head?: unknown) => { - try { - if ( - anchor && - typeof anchor === 'object' && - 'line' in anchor && - 'ch' in anchor - ) { - const anchorPos = convertCodeMirrorPositionToTipTap( - editor, - anchor as Position, - ); - let headPos = anchorPos; - - if ( - head && - typeof head === 'object' && - 'line' in head && - 'ch' in head - ) { - headPos = convertCodeMirrorPositionToTipTap( - editor, - head as Position, - ); - } - - safeExecuteCommand( - () => { - editor.commands.setTextSelection({ - from: anchorPos, - to: headPos, - }); - }, - undefined, - EditorErrorType.COMMAND_EXECUTION_FAILED, - { function: 'setSelection', anchorPos, headPos }, - ); - } else { - editor.commands.focus(); - } - } catch (error) { - handleEditorError( - error as Error, - EditorErrorType.COMMAND_EXECUTION_FAILED, - { - function: 'setSelection', - anchor, - head, - }, - ); - safeExecuteCommand( - () => { - editor.commands.focus(); - }, - undefined, - EditorErrorType.COMMAND_EXECUTION_FAILED, - { function: 'setSelection', isFallback: true }, - ); - } - }, - - setReadOnly: (readOnly: boolean) => { - editor.setEditable(!readOnly); - }, - - replaceRange: (value: string, from?: unknown, to?: unknown) => { - if (from && to && typeof from === 'object' && typeof to === 'object') { - const { from: currentFrom, to: currentTo } = editor.state.selection; - const imageMatch = value.match(MARKDOWN_PATTERNS.IMAGE); - if (imageMatch) { - const [, alt, url] = imageMatch; - safeExecuteCommand( - () => { - editor.commands.insertContentAt( - { from: currentFrom, to: currentTo }, - { - type: 'image', - attrs: { - src: url, - alt: alt || '', - }, - }, - ); - }, - () => { - editor.commands.insertContentAt( - { from: currentFrom, to: currentTo }, - value, - { contentType: 'markdown' }, - ); - }, - ); - return; - } - - safeExecuteCommand(() => { - editor.commands.insertContentAt( - { from: currentFrom, to: currentTo }, - value, - { contentType: 'markdown' }, - ); - }); - } else { - const imageMatch = value.match(MARKDOWN_PATTERNS.IMAGE); - if (imageMatch) { - const [, alt, url] = imageMatch; - safeExecuteCommand( - () => { - editor.commands.insertContent({ - type: 'image', - attrs: { - src: url, - alt: alt || '', - }, - }); - }, - () => { - editor.commands.insertContent(value, { - contentType: 'markdown', - }); - }, - ); - return; - } - - safeExecuteCommand(() => { - editor.commands.insertContent(value, { contentType: 'markdown' }); - }); - } - }, - }; -} diff --git a/ui/src/components/Editor/utils/tiptap/commands.ts b/ui/src/components/Editor/utils/tiptap/commands.ts deleted file mode 100644 index 08e2defc..00000000 --- a/ui/src/components/Editor/utils/tiptap/commands.ts +++ /dev/null @@ -1,720 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Editor as TipTapEditor } from '@tiptap/react'; -import { Command } from '@codemirror/view'; - -import { Level } from '../../types'; - -import { safeExecuteCommand, logWarning } from './errorHandler'; -import { MARKDOWN_PATTERNS } from './constants'; - -/** - * Creates command methods module - * - * Provides command methods for the editor, including: - * - Low-level methods: wrapText, replaceLines, appendBlock (for internal editor use) - * - Semantic methods: insertBold, insertHeading, insertImage, etc. (for toolbar use) - * - State query methods: isBold, isHeading, etc. - * - * @param editor - TipTap editor instance - * @returns Object containing all command methods - */ -export function createCommandMethods(editor: TipTapEditor) { - return { - wrapText: (before: string, after?: string, defaultText?: string) => { - const { from, to } = editor.state.selection; - const actualAfter = after || before; - - if (before === '**' && actualAfter === '**') { - if (from === to) { - if (defaultText) { - const insertPos = from; - editor.commands.insertContent(defaultText); - editor.commands.setTextSelection({ - from: insertPos, - to: insertPos + defaultText.length, - }); - editor.commands.toggleBold(); - } else { - editor.commands.toggleBold(); - } - } else { - editor.commands.toggleBold(); - } - return; - } - - if (before === '*' && actualAfter === '*') { - if (from === to) { - if (defaultText) { - const insertPos = from; - editor.commands.insertContent(defaultText); - editor.commands.setTextSelection({ - from: insertPos, - to: insertPos + defaultText.length, - }); - editor.commands.toggleItalic(); - } else { - editor.commands.toggleItalic(); - } - } else { - editor.commands.toggleItalic(); - } - return; - } - - if (before === '`' && actualAfter === '`') { - if (from === to) { - if (defaultText) { - const insertPos = from; - editor.commands.insertContent(defaultText); - editor.commands.setTextSelection({ - from: insertPos, - to: insertPos + defaultText.length, - }); - editor.commands.toggleCode(); - } else { - editor.commands.toggleCode(); - } - } else { - editor.commands.toggleCode(); - } - return; - } - - if (before === '```\n' && actualAfter === '\n```') { - if (from === to) { - const codeBlockText = defaultText - ? `\`\`\`\n${defaultText}\n\`\`\`` - : '```\n\n```'; - safeExecuteCommand( - () => { - editor.commands.insertContent(codeBlockText, { - contentType: 'markdown', - }); - }, - () => { - editor.commands.insertContent({ - type: 'codeBlock', - content: defaultText - ? [ - { - type: 'text', - text: defaultText, - }, - ] - : [], - }); - }, - ); - } else { - const selectedText = editor.state.doc.textBetween(from, to); - safeExecuteCommand( - () => { - editor.commands.insertContentAt( - { from, to }, - { - type: 'codeBlock', - content: [ - { - type: 'text', - text: selectedText, - }, - ], - }, - ); - }, - () => { - const codeBlockText = `\`\`\`\n${selectedText}\n\`\`\``; - editor.commands.insertContentAt({ from, to }, codeBlockText, { - contentType: 'markdown', - }); - }, - ); - } - return; - } - - if (from === to) { - const text = before + (defaultText || '') + actualAfter; - editor.commands.insertContent(text, { contentType: 'markdown' }); - } else { - const selectedText = editor.state.doc.textBetween(from, to); - const wrappedText = before + selectedText + actualAfter; - editor.commands.insertContentAt({ from, to }, wrappedText, { - contentType: 'markdown', - }); - } - }, - - replaceLines: (replace: Parameters<Array<string>['map']>[0]) => { - const { from } = editor.state.selection; - const $pos = editor.state.doc.resolve(from); - const block = $pos.parent; - const lineText = block.textContent; - const newText = replace(lineText, 0, [lineText]) as string; - - const finalText = newText || ' '; - const headingMatch = finalText.match(MARKDOWN_PATTERNS.HEADING); - if (headingMatch) { - const [, hashes, text] = headingMatch; - const level = hashes.length; - const start = $pos.start($pos.depth); - const end = $pos.end($pos.depth); - - if (start < 0 || end < 0 || start > end) { - logWarning('Invalid position range for heading', { start, end }); - return; - } - - const headingText = text.trim() || 'Heading'; - safeExecuteCommand( - () => { - if (start === end) { - editor.commands.insertContent({ - type: 'heading', - attrs: { level }, - content: [ - { - type: 'text', - text: headingText, - }, - ], - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - { - type: 'heading', - attrs: { level }, - content: [ - { - type: 'text', - text: headingText, - }, - ], - }, - ); - } - }, - () => { - const markdownText = finalText.trim() || `# Heading`; - if (start === end) { - editor.commands.insertContent(markdownText, { - contentType: 'markdown', - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - markdownText, - { contentType: 'markdown' }, - ); - } - }, - ); - return; - } - - if (finalText.startsWith('> ')) { - const quoteText = finalText.slice(2).trim(); - const start = $pos.start($pos.depth); - const end = $pos.end($pos.depth); - - if (start < 0 || end < 0 || start > end) { - logWarning('Invalid position range for heading', { start, end }); - return; - } - - const quoteMarkdown = quoteText ? `> ${quoteText}` : '> '; - safeExecuteCommand( - () => { - if (start === end) { - editor.commands.insertContent(quoteMarkdown, { - contentType: 'markdown', - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - quoteMarkdown, - { contentType: 'markdown' }, - ); - } - }, - () => { - if (start === end) { - editor.commands.insertContent({ - type: 'paragraph', - content: quoteText ? [{ type: 'text', text: quoteText }] : [], - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - { - type: 'paragraph', - content: quoteText ? [{ type: 'text', text: quoteText }] : [], - }, - ); - } - }, - ); - return; - } - - const olMatchOriginal = lineText.match( - MARKDOWN_PATTERNS.ORDERED_LIST_ORIGINAL, - ); - const olMatchNew = finalText.match(MARKDOWN_PATTERNS.ORDERED_LIST_NEW); - - if (olMatchOriginal || olMatchNew) { - const isInOrderedList = editor.isActive('orderedList'); - const start = $pos.start($pos.depth); - const end = $pos.end($pos.depth); - - if (start < 0 || end < 0 || start > end) { - logWarning('Invalid position range for ordered list', { - start, - end, - }); - return; - } - - if (olMatchOriginal && !olMatchNew) { - const textContent = finalText.trim(); - const contentToInsert = textContent || 'Paragraph'; - - safeExecuteCommand( - () => { - if (start === end) { - editor.commands.insertContent(contentToInsert, { - contentType: 'markdown', - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - contentToInsert, - { contentType: 'markdown' }, - ); - } - }, - () => { - if (start === end) { - editor.commands.insertContent({ - type: 'paragraph', - content: [{ type: 'text', text: contentToInsert }], - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - { - type: 'paragraph', - content: [{ type: 'text', text: contentToInsert }], - }, - ); - } - }, - ); - if (isInOrderedList) { - safeExecuteCommand(() => { - editor.chain().focus().toggleOrderedList().run(); - }); - } - } else if (!olMatchOriginal && olMatchNew) { - const [, , text] = olMatchNew; - const textContent = text.trim(); - const contentToInsert = textContent || 'List item'; - - safeExecuteCommand( - () => { - if (start === end) { - editor.commands.insertContent(contentToInsert, { - contentType: 'markdown', - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - contentToInsert, - { contentType: 'markdown' }, - ); - } - }, - () => { - if (start === end) { - editor.commands.insertContent({ - type: 'paragraph', - content: [{ type: 'text', text: contentToInsert }], - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - { - type: 'paragraph', - content: [{ type: 'text', text: contentToInsert }], - }, - ); - } - }, - ); - if (!isInOrderedList) { - safeExecuteCommand(() => { - editor.chain().focus().toggleOrderedList().run(); - }); - } - } - return; - } - const ulMatchOriginal = lineText.match( - MARKDOWN_PATTERNS.UNORDERED_LIST_ORIGINAL, - ); - const ulMatchNew = finalText.match(MARKDOWN_PATTERNS.UNORDERED_LIST_NEW); - - if (ulMatchOriginal || ulMatchNew) { - const isInBulletList = editor.isActive('bulletList'); - const start = $pos.start($pos.depth); - const end = $pos.end($pos.depth); - - if (start < 0 || end < 0 || start > end) { - logWarning('Invalid position range for unordered list', { - start, - end, - }); - return; - } - - if (ulMatchOriginal && !ulMatchNew) { - const textContent = finalText.trim(); - const contentToInsert = textContent || 'Paragraph'; - - safeExecuteCommand( - () => { - if (start === end) { - editor.commands.insertContent(contentToInsert, { - contentType: 'markdown', - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - contentToInsert, - { contentType: 'markdown' }, - ); - } - }, - () => { - if (start === end) { - editor.commands.insertContent({ - type: 'paragraph', - content: [{ type: 'text', text: contentToInsert }], - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - { - type: 'paragraph', - content: [{ type: 'text', text: contentToInsert }], - }, - ); - } - }, - ); - if (isInBulletList) { - safeExecuteCommand(() => { - editor.chain().focus().toggleBulletList().run(); - }); - } - } else if (!ulMatchOriginal && ulMatchNew) { - const [, text] = ulMatchNew; - const textContent = text.trim(); - const contentToInsert = textContent || 'List item'; - - safeExecuteCommand( - () => { - if (start === end) { - editor.commands.insertContent(contentToInsert, { - contentType: 'markdown', - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - contentToInsert, - { contentType: 'markdown' }, - ); - } - }, - () => { - if (start === end) { - editor.commands.insertContent({ - type: 'paragraph', - content: [{ type: 'text', text: contentToInsert }], - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - { - type: 'paragraph', - content: [{ type: 'text', text: contentToInsert }], - }, - ); - } - }, - ); - if (!isInBulletList) { - safeExecuteCommand(() => { - editor.chain().focus().toggleBulletList().run(); - }); - } - } - return; - } - - const start = $pos.start($pos.depth); - const end = $pos.end($pos.depth); - - if (start < 0 || end < 0 || start > end) { - logWarning('Invalid position range', { - start, - end, - function: 'replaceLines', - }); - return; - } - - const contentToInsert = finalText.trim() || ' '; - - safeExecuteCommand( - () => { - if (start === end) { - editor.commands.insertContent(contentToInsert, { - contentType: 'markdown', - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - contentToInsert, - { contentType: 'markdown' }, - ); - } - }, - () => { - if (start === end) { - editor.commands.insertContent({ - type: 'paragraph', - content: [{ type: 'text', text: contentToInsert }], - }); - } else { - editor.commands.insertContentAt( - { from: start, to: end }, - { - type: 'paragraph', - content: [{ type: 'text', text: contentToInsert }], - }, - ); - } - }, - ); - }, - - appendBlock: (content: string) => { - if (MARKDOWN_PATTERNS.HORIZONTAL_RULE.test(content.trim())) { - safeExecuteCommand( - () => { - editor.commands.insertContent({ - type: 'horizontalRule', - }); - }, - () => { - editor.commands.insertContent(content, { - contentType: 'markdown', - }); - }, - ); - return; - } - - safeExecuteCommand(() => { - editor.commands.insertContent(`\n\n${content}`, { - contentType: 'markdown', - }); - }); - }, - - addKeyMap: (keyMap: Record<string, Command>) => { - Object.keys(keyMap).forEach(() => {}); - }, - insertBold: (text?: string) => { - if (text) { - const { from } = editor.state.selection; - editor.commands.insertContent(text); - editor.commands.setTextSelection({ from, to: from + text.length }); - } - editor.commands.toggleBold(); - }, - - insertItalic: (text?: string) => { - if (text) { - const { from } = editor.state.selection; - editor.commands.insertContent(text); - editor.commands.setTextSelection({ from, to: from + text.length }); - } - editor.commands.toggleItalic(); - }, - - insertCode: (text?: string) => { - if (text) { - const { from } = editor.state.selection; - editor.commands.insertContent(text); - editor.commands.setTextSelection({ from, to: from + text.length }); - } - editor.commands.toggleCode(); - }, - - insertStrikethrough: (text?: string) => { - if (text) { - const { from } = editor.state.selection; - editor.commands.insertContent(text); - editor.commands.setTextSelection({ from, to: from + text.length }); - } - editor.commands.toggleStrike(); - }, - - insertHeading: (level: Level, text?: string) => { - if (text) { - // Insert heading using TipTap's native API to ensure proper structure - safeExecuteCommand( - () => { - editor.commands.insertContent({ - type: 'heading', - attrs: { level }, - content: [ - { - type: 'text', - text, - }, - ], - }); - // Select only the text part (excluding the heading node structure) - // After insertion, the cursor is at the end of the heading - // We need to select backwards from the current position - const { to } = editor.state.selection; - editor.commands.setTextSelection({ - from: to - text.length, - to, - }); - }, - () => { - // Fallback: use markdown format - const headingText = `${'#'.repeat(level)} ${text}`; - editor.commands.insertContent(headingText, { - contentType: 'markdown', - }); - }, - ); - } else { - editor.commands.toggleHeading({ level }); - } - }, - - insertBlockquote: (text?: string) => { - if (text) { - const { from } = editor.state.selection; - const blockquoteText = `> ${text}`; - - // Use chain to ensure selection happens after insertion - editor - .chain() - .focus() - .insertContent(blockquoteText, { contentType: 'markdown' }) - .setTextSelection({ - from: from + 1, - to: from + 1 + text.length, - }) - .run(); - } else { - editor.commands.toggleBlockquote(); - } - }, - - insertCodeBlock: (language?: string, code?: string) => { - const lang = language || ''; - const codeText = code || 'code here'; - editor.commands.insertContent(`\`\`\`${lang}\n${codeText}\n\`\`\``, { - contentType: 'markdown', - }); - }, - - insertHorizontalRule: () => { - editor.commands.setHorizontalRule(); - }, - - insertOrderedList: () => { - editor.commands.toggleOrderedList(); - }, - - insertUnorderedList: () => { - editor.commands.toggleBulletList(); - }, - - toggleOrderedList: () => { - editor.commands.toggleOrderedList(); - }, - - toggleUnorderedList: () => { - editor.commands.toggleBulletList(); - }, - - insertLink: (url: string, text?: string) => { - const linkText = text || url; - editor.commands.insertContent(`[${linkText}](${url})`, { - contentType: 'markdown', - }); - }, - - insertImage: (url: string, alt?: string) => { - editor.commands.setImage({ src: url, alt: alt || 'image' }); - }, - - insertTable: (rows = 3, cols = 3) => { - editor.commands.insertTable({ - rows, - cols, - withHeaderRow: true, - }); - }, - - indent: () => { - editor.commands.sinkListItem('listItem'); - }, - - outdent: () => { - editor.commands.liftListItem('listItem'); - }, - - isBold: () => editor.isActive('bold'), - isItalic: () => editor.isActive('italic'), - isHeading: (level?: number) => { - if (level) { - return editor.isActive('heading', { level }); - } - return editor.isActive('heading'); - }, - isBlockquote: () => editor.isActive('blockquote'), - isCodeBlock: () => editor.isActive('codeBlock'), - isOrderedList: () => editor.isActive('orderedList'), - isUnorderedList: () => editor.isActive('bulletList'), - }; -} diff --git a/ui/src/components/Editor/utils/tiptap/constants.ts b/ui/src/components/Editor/utils/tiptap/constants.ts deleted file mode 100644 index a4ff7de4..00000000 --- a/ui/src/components/Editor/utils/tiptap/constants.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Markdown pattern matching regular expression constants - * - * Defines regular expression patterns for parsing and matching Markdown syntax. - * These patterns are used to convert Markdown syntax to TipTap nodes, or from TipTap nodes - * to Markdown format. - * - * @example - * ```typescript - * const headingMatch = text.match(MARKDOWN_PATTERNS.HEADING); - * if (headingMatch) { - * const level = headingMatch[1].length; // Number of # - * const text = headingMatch[2]; // Heading text - * } - * ``` - */ -export const MARKDOWN_PATTERNS = { - HEADING: /^(#{1,6})\s+(.+)$/, - ORDERED_LIST_ORIGINAL: /^(\s{0,})(\d+)\.\s/, - ORDERED_LIST_NEW: /^(\d+)\.\s*(.*)$/, - UNORDERED_LIST_ORIGINAL: /^(\s{0,})(-|\*)\s/, - UNORDERED_LIST_NEW: /^[-*]\s*(.*)$/, - INLINE_CODE: /^`(.+?)`$/, - CODE_BLOCK: /^(\n)?```(\w+)?\n([\s\S]*?)\n```(\n)?$/, - IMAGE: /^!\[([^\]]*)\]\(([^)]+)\)$/, - LINK: /^\[([^\]]*)\]\(([^)]+)\)$/, - AUTO_LINK: /^<(.+?)>$/, - HORIZONTAL_RULE: /^-{3,}$/, -} as const; diff --git a/ui/src/components/Editor/utils/tiptap/errorHandler.ts b/ui/src/components/Editor/utils/tiptap/errorHandler.ts deleted file mode 100644 index c8f4e7a3..00000000 --- a/ui/src/components/Editor/utils/tiptap/errorHandler.ts +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Editor error type enumeration - * - * Defines various error types that may occur in the editor, used for error classification and handling. - */ -export enum EditorErrorType { - COMMAND_EXECUTION_FAILED = 'COMMAND_EXECUTION_FAILED', - POSITION_CONVERSION_FAILED = 'POSITION_CONVERSION_FAILED', - CONTENT_PARSING_FAILED = 'CONTENT_PARSING_FAILED', - EVENT_LISTENER_FAILED = 'EVENT_LISTENER_FAILED', -} - -/** - * Editor error interface - */ -export interface EditorError { - type: EditorErrorType; - message: string; - originalError?: Error; - context?: Record<string, unknown>; - timestamp: number; -} - -/** - * Handles editor errors with unified log format - * - * Unified error handling for the editor, recording error information, context, and stack traces - * for easier problem identification and debugging. - * - * @param error - Original error object - * @param type - Error type - * @param context - Optional context information (function name, parameters, etc.) - * @returns Processed error object - * - * @example - * ```typescript - * try { - * editor.commands.insertContent(content); - * } catch (error) { - * handleEditorError(error, EditorErrorType.COMMAND_EXECUTION_FAILED, { - * function: 'insertContent', - * content: content.substring(0, 50), - * }); - * } - * ``` - */ -export function handleEditorError( - error: Error, - type: EditorErrorType, - context?: Record<string, unknown>, -): EditorError { - const editorError: EditorError = { - type, - message: error.message, - originalError: error, - context, - timestamp: Date.now(), - }; - - console.error(`[Editor Error] ${type}:`, { - message: editorError.message, - context: editorError.context, - stack: error.stack, - }); - - return editorError; -} - -/** - * Safely executes TipTap command with error handling and fallback strategy - * - * Automatically catches errors when executing TipTap commands. If a fallback function is provided, - * it attempts to execute the fallback operation when the main command fails. All errors are uniformly recorded. - * - * @param command - Main command function to execute - * @param fallback - Optional fallback function to execute when main command fails - * @param errorType - Error type, defaults to COMMAND_EXECUTION_FAILED - * @param context - Optional context information - * @returns Command execution result, returns undefined if failed and no fallback - * - * @example - * ```typescript - * const result = safeExecuteCommand( - * () => editor.commands.insertContent(content), - * () => editor.commands.insertContent(content, { contentType: 'markdown' }), - * EditorErrorType.COMMAND_EXECUTION_FAILED, - * { function: 'insertContent', contentLength: content.length } - * ); - * ``` - */ -export function safeExecuteCommand<T>( - command: () => T, - fallback?: () => T, - errorType: EditorErrorType = EditorErrorType.COMMAND_EXECUTION_FAILED, - context?: Record<string, unknown>, -): T | undefined { - try { - return command(); - } catch (error) { - handleEditorError(error as Error, errorType, context); - if (fallback) { - try { - return fallback(); - } catch (fallbackError) { - handleEditorError(fallbackError as Error, errorType, { - ...context, - isFallback: true, - }); - } - } - return undefined; - } -} - -/** - * Logs warning information (for non-fatal errors) - * - * Records non-fatal warning information to alert potential issues without affecting functionality. - * - * @param message - Warning message - * @param context - Optional context information - * - * @example - * ```typescript - * if (start < 0 || end < 0) { - * logWarning('Invalid position range', { start, end, function: 'setSelection' }); - * return; - * } - * ``` - */ -export function logWarning( - message: string, - context?: Record<string, unknown>, -): void { - console.warn(`[Editor Warning] ${message}`, context || {}); -} diff --git a/ui/src/components/Editor/utils/tiptap/events.ts b/ui/src/components/Editor/utils/tiptap/events.ts deleted file mode 100644 index 2a86440d..00000000 --- a/ui/src/components/Editor/utils/tiptap/events.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Editor as TipTapEditor } from '@tiptap/react'; - -import { logWarning } from './errorHandler'; - -/** - * Checks if editor view is available - */ -function isViewAvailable(editor: TipTapEditor): boolean { - if (!editor) { - return false; - } - if (editor.isDestroyed) { - return false; - } - return !!(editor.view && editor.state); -} - -/** - * Creates event handling methods module - * - * Provides event handling methods for the editor, including: - * - on: Register event listeners (change, focus, blur, dragenter, dragover, drop, paste) - * - off: Remove event listeners - * - * Note: For DOM events (dragenter, dragover, drop, paste), - * the editor view must be mounted before binding events. - * - * @param editor - TipTap editor instance - * @returns Object containing event handling methods - */ -export function createEventMethods(editor: TipTapEditor) { - return { - on: (event: string, callback: (e?: unknown) => void) => { - if (event === 'change') { - editor.on('update', callback); - } else if (event === 'focus') { - editor.on('focus', callback); - } else if (event === 'blur') { - editor.on('blur', callback); - } else if ( - event === 'dragenter' || - event === 'dragover' || - event === 'drop' || - event === 'paste' - ) { - if (!isViewAvailable(editor)) { - logWarning( - 'TipTap editor view is not available yet. Event listener not attached.', - { - event, - }, - ); - return; - } - editor.view.dom.addEventListener(event, callback as EventListener); - } - }, - - off: (event: string, callback: (e?: unknown) => void) => { - if ( - (event === 'dragenter' || - event === 'dragover' || - event === 'drop' || - event === 'paste') && - !isViewAvailable(editor) - ) { - return; - } - if (event === 'change') { - editor.off('update', callback); - } else if (event === 'focus') { - editor.off('focus', callback); - } else if (event === 'blur') { - editor.off('blur', callback); - } else if ( - event === 'dragenter' || - event === 'dragover' || - event === 'drop' || - event === 'paste' - ) { - editor.view.dom.removeEventListener(event, callback as EventListener); - } - }, - }; -} diff --git a/ui/src/components/Editor/utils/tiptap/position.ts b/ui/src/components/Editor/utils/tiptap/position.ts deleted file mode 100644 index 378908b8..00000000 --- a/ui/src/components/Editor/utils/tiptap/position.ts +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Editor as TipTapEditor } from '@tiptap/react'; - -import { Position } from '../../types'; - -import { handleEditorError, EditorErrorType } from './errorHandler'; - -/** - * Converts TipTap position to CodeMirror Position - * - * TipTap uses document tree-based node positions (character index), while CodeMirror uses - * line-based positions (line number and column number). This function converts between them. - * - * @param editor - TipTap editor instance - * @param pos - TipTap position index (character position) - * @returns CodeMirror position object with line and ch properties - * - * @example - * ```typescript - * const tipTapPos = 100; // Character position - * const codeMirrorPos = convertTipTapPositionToCodeMirror(editor, tipTapPos); - * // { line: 5, ch: 10 } - * ``` - */ -export function convertTipTapPositionToCodeMirror( - editor: TipTapEditor, - pos: number, -): Position { - try { - const { doc } = editor.state; - let line = 0; - let ch = 0; - let currentPos = 0; - - for (let i = 0; i < doc.content.childCount; i += 1) { - const child = doc.content.child(i); - const childSize = child.nodeSize; - - if (currentPos + childSize > pos) { - const text = child.textContent; - const relativePos = pos - currentPos; - - const textBeforePos = text.substring(0, relativePos); - const newlineMatches = textBeforePos.match(/\n/g); - line += newlineMatches ? newlineMatches.length : 0; - ch = relativePos - textBeforePos.lastIndexOf('\n') - 1; - break; - } - - const text = child.textContent; - const newlineMatches = text.match(/\n/g); - line += newlineMatches ? newlineMatches.length : 0; - currentPos += childSize; - } - - return { line, ch }; - } catch (error) { - handleEditorError( - error as Error, - EditorErrorType.POSITION_CONVERSION_FAILED, - { - function: 'convertTipTapPositionToCodeMirror', - position: pos, - }, - ); - return { line: 0, ch: 0 }; - } -} - -/** - * Converts CodeMirror Position to TipTap position index - * - * Converts CodeMirror's line-based position to TipTap's character index position. - * - * @param editor - TipTap editor instance - * @param position - CodeMirror position object with line and ch properties - * @returns TipTap position index (character position) - * - * @example - * ```typescript - * const codeMirrorPos = { line: 5, ch: 10 }; - * const tipTapPos = convertCodeMirrorPositionToTipTap(editor, codeMirrorPos); - * // 100 (character position) - * ``` - */ -export function convertCodeMirrorPositionToTipTap( - editor: TipTapEditor, - position: Position, -): number { - try { - const { doc } = editor.state; - let currentLine = 0; - let currentPos = 0; - - for (let i = 0; i < doc.content.childCount; i += 1) { - const child = doc.content.child(i); - const text = child.textContent; - const lines = text.split('\n'); - - if (currentLine + lines.length - 1 >= position.line) { - const lineInNode = position.line - currentLine; - const { ch: posInLine } = position; - - let pos = 0; - for (let j = 0; j < lineInNode; j += 1) { - pos += lines[j].length + 1; // +1 for newline - } - pos += posInLine; - - return currentPos + pos; - } - - currentLine += lines.length - 1; - currentPos += child.nodeSize; - } - - return doc.content.size; - } catch (error) { - handleEditorError( - error as Error, - EditorErrorType.POSITION_CONVERSION_FAILED, - { - function: 'convertCodeMirrorPositionToTipTap', - position, - }, - ); - return editor.state.doc.content.size; - } -} diff --git a/ui/src/components/Editor/utils/tiptap/tableExtension.ts b/ui/src/components/Editor/utils/tiptap/tableExtension.ts deleted file mode 100644 index 70e68f77..00000000 --- a/ui/src/components/Editor/utils/tiptap/tableExtension.ts +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Table, TableOptions } from '@tiptap/extension-table'; -import type { NodeViewRendererProps } from '@tiptap/core'; - -interface TableWrapperOptions extends TableOptions { - wrapperClass?: string; -} - -export const TableWithWrapper = Table.extend<TableWrapperOptions>({ - addOptions() { - const parentOptions = (this.parent?.() || {}) as Partial<TableOptions>; - return { - ...parentOptions, - HTMLAttributes: parentOptions.HTMLAttributes || {}, - wrapperClass: 'table-responsive', - } as TableWrapperOptions; - }, - - addNodeView() { - return (props: NodeViewRendererProps) => { - const { node } = props; - const wrapperClass = this.options.wrapperClass || 'table-responsive'; - - const dom = document.createElement('div'); - dom.className = wrapperClass; - - const table = document.createElement('table'); - - const htmlAttrs = this.options.HTMLAttributes || {}; - if (htmlAttrs.class) { - table.className = htmlAttrs.class as string; - } - if (htmlAttrs.style && typeof htmlAttrs.style === 'object') { - Object.assign(table.style, htmlAttrs.style); - } - - const colgroup = document.createElement('colgroup'); - if (node.firstChild) { - const { childCount } = node.firstChild; - for (let i = 0; i < childCount; i += 1) { - const col = document.createElement('col'); - colgroup.appendChild(col); - } - } - table.appendChild(colgroup); - - const tbody = document.createElement('tbody'); - table.appendChild(tbody); - dom.appendChild(table); - - return { - dom, - contentDOM: tbody, - update: (updatedNode) => { - if (updatedNode.type !== node.type) { - return false; - } - return true; - }, - }; - }; - }, -});
