From 2f1215b0634ed4198a282d828e744f9a25a39c0d Mon Sep 17 00:00:00 2001 From: Innei Date: Thu, 1 Feb 2024 00:00:46 +0800 Subject: [PATCH 1/6] init --- package.json | 6 + pnpm-lock.yaml | 325 +++++++++++++++++ .../editor/Milkdown/MilkdownEditor.tsx | 133 ------- .../modules/dashboard/writing/Writing.tsx | 4 +- .../ui/editor/Milkdown/MilkdownEditor.tsx | 332 ++++++++++++++++++ .../editor/Milkdown/index.module.css | 0 .../dashboard => ui}/editor/Milkdown/index.ts | 0 .../ui/editor/Milkdown/plugins/strike.ts | 33 ++ src/components/ui/editor/index.demo.tsx | 60 ++++ .../{modules/dashboard => ui}/editor/index.ts | 0 storybook/package.json | 1 + storybook/pnpm-lock.yaml | 7 +- ....timestamp-1706716056463-9580bc4ee8dca.mjs | 0 ....timestamp-1706716345357-37f068121814c.mjs | 55 +++ ....timestamp-1706716552729-c966d43f7c18e.mjs | 0 15 files changed, 817 insertions(+), 139 deletions(-) delete mode 100644 src/components/modules/dashboard/editor/Milkdown/MilkdownEditor.tsx create mode 100644 src/components/ui/editor/Milkdown/MilkdownEditor.tsx rename src/components/{modules/dashboard => ui}/editor/Milkdown/index.module.css (100%) rename src/components/{modules/dashboard => ui}/editor/Milkdown/index.ts (100%) create mode 100644 src/components/ui/editor/Milkdown/plugins/strike.ts create mode 100644 src/components/ui/editor/index.demo.tsx rename src/components/{modules/dashboard => ui}/editor/index.ts (100%) create mode 100644 storybook/vite.config.mts.timestamp-1706716056463-9580bc4ee8dca.mjs create mode 100644 storybook/vite.config.mts.timestamp-1706716345357-37f068121814c.mjs create mode 100644 storybook/vite.config.mts.timestamp-1706716552729-c966d43f7c18e.mjs diff --git a/package.json b/package.json index 420c98b0e4..d1ed150844 100644 --- a/package.json +++ b/package.json @@ -41,14 +41,18 @@ "@excalidraw/excalidraw": "0.17.2", "@floating-ui/react-dom": "2.0.8", "@milkdown/core": "7.3.3", + "@milkdown/ctx": "7.3.3", "@milkdown/plugin-clipboard": "7.3.3", "@milkdown/plugin-history": "7.3.3", "@milkdown/plugin-indent": "7.3.3", "@milkdown/plugin-listener": "7.3.3", "@milkdown/preset-commonmark": "7.3.3", + "@milkdown/preset-gfm": "7.3.3", + "@milkdown/prose": "7.3.3", "@milkdown/react": "7.3.3", "@milkdown/utils": "7.3.3", "@mx-space/api-client": "1.7.2", + "@prosemirror-adapter/react": "0.2.6", "@radix-ui/react-dialog": "1.0.5", "@radix-ui/react-label": "2.0.2", "@radix-ui/react-scroll-area": "1.0.5", @@ -97,12 +101,14 @@ "react-toastify": "10.0.4", "react-tweet": "3.2.0", "react-wrap-balancer": "1.1.0", + "remark-directive": "3.0.0", "remove-markdown": "0.5.0", "server-only": "^0.0.1", "socket.io-client": "4.7.4", "tailwind-merge": "2.2.1", "unidata.js": "0.8.0", "uniqolor": "1.1.1", + "unist-util-visit": "5.0.0", "use-context-selector": "1.4.1", "vaul": "0.8.9", "xss": "1.0.14" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b877edfd34..a0963fbe73 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ dependencies: '@milkdown/core': specifier: 7.3.3 version: 7.3.3(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3) + '@milkdown/ctx': + specifier: 7.3.3 + version: 7.3.3 '@milkdown/plugin-clipboard': specifier: 7.3.3 version: 7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3) @@ -47,6 +50,12 @@ dependencies: '@milkdown/preset-commonmark': specifier: 7.3.3 version: 7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3) + '@milkdown/preset-gfm': + specifier: 7.3.3 + version: 7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/preset-commonmark@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3) + '@milkdown/prose': + specifier: 7.3.3 + version: 7.3.3 '@milkdown/react': specifier: 7.3.3 version: 7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3)(react-dom@18.2.0)(react@18.2.0) @@ -56,6 +65,9 @@ dependencies: '@mx-space/api-client': specifier: 1.7.2 version: 1.7.2 + '@prosemirror-adapter/react': + specifier: 0.2.6 + version: 0.2.6(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-dialog': specifier: 1.0.5 version: 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) @@ -200,6 +212,9 @@ dependencies: react-wrap-balancer: specifier: 1.1.0 version: 1.1.0(react@18.2.0) + remark-directive: + specifier: 3.0.0 + version: 3.0.0 remove-markdown: specifier: 0.5.0 version: 0.5.0 @@ -218,6 +233,9 @@ dependencies: uniqolor: specifier: 1.1.1 version: 1.1.1 + unist-util-visit: + specifier: 5.0.0 + version: 5.0.0 use-context-selector: specifier: 1.4.1 version: 1.4.1(react-dom@18.2.0)(react@18.2.0)(scheduler@0.23.0) @@ -1736,6 +1754,28 @@ packages: unist-util-visit: 5.0.0 dev: false + /@milkdown/preset-gfm@7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/preset-commonmark@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3): + resolution: {integrity: sha512-n5hkuSEPcAe3jAVcvs7gqOgHLR3OEW6+vLfapF4IgD44pF+U9eBLTrmcysVMLRzxXNzzbCqlgofkoye3XVsgew==} + peerDependencies: + '@milkdown/core': ^7.2.0 + '@milkdown/ctx': ^7.2.0 + '@milkdown/preset-commonmark': ^7.2.0 + '@milkdown/prose': ^7.2.0 + '@milkdown/transformer': ^7.2.0 + dependencies: + '@milkdown/core': 7.3.3(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3) + '@milkdown/ctx': 7.3.3 + '@milkdown/exception': 7.3.3 + '@milkdown/preset-commonmark': 7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3) + '@milkdown/prose': 7.3.3 + '@milkdown/transformer': 7.3.3(@milkdown/prose@7.3.3) + '@milkdown/utils': 7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3) + remark-gfm: 4.0.0 + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + dev: false + /@milkdown/prose@7.3.3: resolution: {integrity: sha512-d+Dv2C7cSWBfkG3scLnc+6IA40nKNIJM37NFBQ6mbOW7/6dj1m5vhNGZN+LDKlEEYOhVko+Kr6vwI4FfuY+pUw==} dependencies: @@ -2092,6 +2132,25 @@ packages: resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==} dev: true + /@prosemirror-adapter/core@0.2.6: + resolution: {integrity: sha512-7GXWQBR/bd6ngvek8SgtlEVC0x3KL7LKZ5cxyZl4IBAlRDbITQWsuKLChEXNan9A6+9Ry4a46crbDGTQlzooOg==} + dependencies: + tslib: 2.6.2 + dev: false + + /@prosemirror-adapter/react@0.2.6(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-JdDqAJV7FnRyIlnXPP+E0Iu80BQPvHeB+7c0ZfdcHLfVb2BLTNHk6iOoqJmBJmqqHt/KjxXXTmxRUS4EEsjVlg==} + peerDependencies: + react: '*' + react-dom: '*' + dependencies: + '@prosemirror-adapter/core': 0.2.6 + nanoid: 4.0.2 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tslib: 2.6.2 + dev: false + /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} dependencies: @@ -3734,6 +3793,10 @@ packages: /caniuse-lite@1.0.30001579: resolution: {integrity: sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==} + /ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + dev: false + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -3755,10 +3818,22 @@ packages: engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} dev: true + /character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + dev: false + + /character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + dev: false + /character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} dev: false + /character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + dev: false + /charenc@0.0.2: resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} dev: false @@ -5514,6 +5589,17 @@ packages: loose-envify: 1.4.0 dev: false + /is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + dev: false + + /is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + dev: false + /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} dependencies: @@ -5576,6 +5662,10 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + dev: false + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -5618,6 +5708,10 @@ packages: is-extglob: 2.1.1 dev: true + /is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + dev: false + /is-map@2.0.2: resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==} dev: true @@ -6165,6 +6259,10 @@ packages: resolution: {integrity: sha512-Trz4v0+XWlwy68LJIyw3bLbsJiC8XAbRCKF9DbEtZjyndKOGVx6n+wNB0VfoRmY2LKboQLeniap3xrb6LGSJ8A==} dev: false + /markdown-table@3.0.3: + resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} + dev: false + /marked@11.2.0: resolution: {integrity: sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==} engines: {node: '>= 18'} @@ -6187,6 +6285,30 @@ packages: unist-util-visit: 5.0.0 dev: false + /mdast-util-directive@3.0.0: + resolution: {integrity: sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q==} + dependencies: + '@types/mdast': 4.0.3 + '@types/unist': 3.0.2 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.0 + mdast-util-to-markdown: 2.1.0 + parse-entities: 4.0.1 + stringify-entities: 4.0.3 + unist-util-visit-parents: 6.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-find-and-replace@3.0.1: + resolution: {integrity: sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==} + dependencies: + '@types/mdast': 4.0.3 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 + dev: false + /mdast-util-from-markdown@1.3.1: resolution: {integrity: sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==} dependencies: @@ -6225,6 +6347,75 @@ packages: - supports-color dev: false + /mdast-util-gfm-autolink-literal@2.0.0: + resolution: {integrity: sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==} + dependencies: + '@types/mdast': 4.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.1 + micromark-util-character: 2.0.1 + dev: false + + /mdast-util-gfm-footnote@2.0.0: + resolution: {integrity: sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==} + dependencies: + '@types/mdast': 4.0.3 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.0 + mdast-util-to-markdown: 2.1.0 + micromark-util-normalize-identifier: 2.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + dependencies: + '@types/mdast': 4.0.3 + mdast-util-from-markdown: 2.0.0 + mdast-util-to-markdown: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + dependencies: + '@types/mdast': 4.0.3 + devlop: 1.1.0 + markdown-table: 3.0.3 + mdast-util-from-markdown: 2.0.0 + mdast-util-to-markdown: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + dependencies: + '@types/mdast': 4.0.3 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.0 + mdast-util-to-markdown: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-gfm@3.0.0: + resolution: {integrity: sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==} + dependencies: + mdast-util-from-markdown: 2.0.0 + mdast-util-gfm-autolink-literal: 2.0.0 + mdast-util-gfm-footnote: 2.0.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.0 + transitivePeerDependencies: + - supports-color + dev: false + /mdast-util-phrasing@4.0.0: resolution: {integrity: sha512-xadSsJayQIucJ9n053dfQwVu1kuXg7jCTdYsMK8rqzKZh52nLfSH/k0sAxE0u+pj/zKZX+o5wB+ML5mRayOxFA==} dependencies: @@ -6339,6 +6530,90 @@ packages: micromark-util-types: 2.0.0 dev: false + /micromark-extension-directive@3.0.0: + resolution: {integrity: sha512-61OI07qpQrERc+0wEysLHMvoiO3s2R56x5u7glHq2Yqq6EHbH4dW25G9GfDdGCDYqA21KE6DWgNSzxSwHc2hSg==} + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.0 + micromark-factory-whitespace: 2.0.0 + micromark-util-character: 2.0.1 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + parse-entities: 4.0.1 + dev: false + + /micromark-extension-gfm-autolink-literal@2.0.0: + resolution: {integrity: sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==} + dependencies: + micromark-util-character: 2.0.1 + micromark-util-sanitize-uri: 2.0.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm-footnote@2.0.0: + resolution: {integrity: sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==} + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.0 + micromark-factory-space: 2.0.0 + micromark-util-character: 2.0.1 + micromark-util-normalize-identifier: 2.0.0 + micromark-util-sanitize-uri: 2.0.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==} + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.0 + micromark-util-classify-character: 2.0.0 + micromark-util-resolve-all: 2.0.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm-table@2.0.0: + resolution: {integrity: sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==} + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.0 + micromark-util-character: 2.0.1 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + dependencies: + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm-task-list-item@2.0.1: + resolution: {integrity: sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==} + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.0 + micromark-util-character: 2.0.1 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + + /micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + dependencies: + micromark-extension-gfm-autolink-literal: 2.0.0 + micromark-extension-gfm-footnote: 2.0.0 + micromark-extension-gfm-strikethrough: 2.0.0 + micromark-extension-gfm-table: 2.0.0 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.0.1 + micromark-util-combine-extensions: 2.0.0 + micromark-util-types: 2.0.0 + dev: false + /micromark-factory-destination@1.1.0: resolution: {integrity: sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==} dependencies: @@ -6744,6 +7019,12 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + /nanoid@4.0.2: + resolution: {integrity: sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==} + engines: {node: ^14 || ^16 || >=18} + hasBin: true + dev: false + /nanoid@5.0.4: resolution: {integrity: sha512-vAjmBf13gsmhXSgBrtIclinISzFFy22WwCYoyilZlsrRXNIHSwgFQ1bEdjRwMT3aoadeIF6HMuDRlOxzfXV8ig==} engines: {node: ^18 || >=20} @@ -6989,6 +7270,19 @@ packages: author-regex: 1.0.0 dev: true + /parse-entities@4.0.1: + resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==} + dependencies: + '@types/unist': 2.0.10 + character-entities: 2.0.2 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.0.2 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + dev: false + /parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -7988,6 +8282,30 @@ packages: set-function-name: 2.0.1 dev: true + /remark-directive@3.0.0: + resolution: {integrity: sha512-l1UyWJ6Eg1VPU7Hm/9tt0zKtReJQNOA4+iDMAxTyZNWnJnFlbS/7zhiel/rogTLQ2vMYwDzSJa4BiVNqGlqIMA==} + dependencies: + '@types/mdast': 4.0.3 + mdast-util-directive: 3.0.0 + micromark-extension-directive: 3.0.0 + unified: 11.0.4 + transitivePeerDependencies: + - supports-color + dev: false + + /remark-gfm@4.0.0: + resolution: {integrity: sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==} + dependencies: + '@types/mdast': 4.0.3 + mdast-util-gfm: 3.0.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.4 + transitivePeerDependencies: + - supports-color + dev: false + /remark-inline-links@7.0.0: resolution: {integrity: sha512-4uj1pPM+F495ySZhTIB6ay2oSkTsKgmYaKk/q5HIdhX2fuyLEegpjWa0VdJRJ01sgOqAFo7MBKdDUejIYBMVMQ==} dependencies: @@ -8418,6 +8736,13 @@ packages: es-abstract: 1.22.3 dev: true + /stringify-entities@4.0.3: + resolution: {integrity: sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==} + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + dev: false + /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} diff --git a/src/components/modules/dashboard/editor/Milkdown/MilkdownEditor.tsx b/src/components/modules/dashboard/editor/Milkdown/MilkdownEditor.tsx deleted file mode 100644 index 322bb7cdd4..0000000000 --- a/src/components/modules/dashboard/editor/Milkdown/MilkdownEditor.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import { Milkdown, MilkdownProvider, useEditor } from '@milkdown/react' -import { - forwardRef, - useCallback, - useId, - useImperativeHandle, - useRef, -} from 'react' -import type { Config } from '@milkdown/core' - -import { - defaultValueCtx, - Editor, - EditorStatus, - editorViewCtx, - editorViewOptionsCtx, - rootCtx, - serializerCtx, -} from '@milkdown/core' -import { clipboard } from '@milkdown/plugin-clipboard' -import { history } from '@milkdown/plugin-history' -import { indent } from '@milkdown/plugin-indent' -import { listener, listenerCtx } from '@milkdown/plugin-listener' -import { commonmark } from '@milkdown/preset-commonmark' -import { replaceAll } from '@milkdown/utils' - -import { useIsUnMounted } from '~/hooks/common/use-is-unmounted' - -import styles from './index.module.css' - -export interface MilkdownProps { - initialMarkdown?: string - readonly?: boolean - onBlur?(): void - onChange?(e: { target: { value: string } }): void - onMarkdownChange?(markdown: string): void - onCreated?(): void -} - -export interface MilkdownRef { - getMarkdown(): string | undefined - setMarkdown(markdown: string): void -} - -export const MilkdownEditor = forwardRef( - (props, ref) => { - return ( - - - - ) - }, -) - -MilkdownEditor.displayName = 'MilkdownEditor' - -const MilkdownEditorImpl = forwardRef( - (props, ref) => { - const { initialMarkdown } = props - - const editorCtxRef = useRef[0]>() - const editorRef = useRef() - const getMarkdown = useCallback( - () => - editorRef.current?.action((ctx) => { - const editorView = ctx.get(editorViewCtx) - const serializer = ctx.get(serializerCtx) - return serializer(editorView.state.doc) - }), - [], - ) - const { get } = useEditor((root) => { - const editor = Editor.make() - editorRef.current = editor - - return editor - .config((ctx) => { - editorCtxRef.current = ctx - - ctx.set(rootCtx, root) - ctx.set(defaultValueCtx, initialMarkdown || '') - editorCtxRef.current.update(editorViewOptionsCtx, (ctx) => ({ - ...ctx, - editable: () => !props.readonly, - })) - - ctx - .get(listenerCtx) - .markdownUpdated((ctx, markdown) => { - if (isUnMounted.current) return - - props.onMarkdownChange?.(markdown) - props.onChange?.({ target: { value: markdown } }) - }) - .blur(() => { - props.onBlur?.() - }) - }) - .use(commonmark) - .use(listener) - .use(clipboard) - .use(history) - .use(indent) - .onStatusChange((o) => { - if (o === EditorStatus.Created) { - props.onCreated?.() - } - }) - }, []) - - const setMarkdown = useCallback( - (markdown: string) => { - get()?.action(replaceAll(markdown)) - }, - [get], - ) - - useImperativeHandle(ref, () => ({ - getMarkdown, - setMarkdown, - })) - - const isUnMounted = useIsUnMounted() - - const id = useId() - return ( -
- -
- ) - }, -) -MilkdownEditorImpl.displayName = 'MilkdownEditorImpl' diff --git a/src/components/modules/dashboard/writing/Writing.tsx b/src/components/modules/dashboard/writing/Writing.tsx index 6d4bdb496f..ca335a9ad5 100644 --- a/src/components/modules/dashboard/writing/Writing.tsx +++ b/src/components/modules/dashboard/writing/Writing.tsx @@ -2,13 +2,13 @@ import React, { useEffect, useRef } from 'react' import { produce } from 'immer' import { atom, useAtomValue, useSetAtom, useStore } from 'jotai' import type { FC } from 'react' -import type { MilkdownRef } from '../editor' +import type { MilkdownRef } from '../../../ui/editor' import { useEventCallback } from '~/hooks/common/use-event-callback' import { clsxm } from '~/lib/helper' import { jotaiStore } from '~/lib/store' -import { MilkdownEditor } from '../editor' +import { MilkdownEditor } from '../../../ui/editor' import { useBaseWritingContext } from './BaseWritingProvider' import { TitleInput } from './TitleInput' diff --git a/src/components/ui/editor/Milkdown/MilkdownEditor.tsx b/src/components/ui/editor/Milkdown/MilkdownEditor.tsx new file mode 100644 index 0000000000..3f8d2012a6 --- /dev/null +++ b/src/components/ui/editor/Milkdown/MilkdownEditor.tsx @@ -0,0 +1,332 @@ +import { Milkdown, MilkdownProvider, useEditor } from '@milkdown/react' +import { + ProsemirrorAdapterProvider, + useNodeViewContext, + useNodeViewFactory, +} from '@prosemirror-adapter/react' +import { + forwardRef, + useCallback, + useId, + useImperativeHandle, + useRef, +} from 'react' +import directive from 'remark-directive' +import type { Config } from '@milkdown/core' +import type { MilkdownPlugin } from '@milkdown/ctx' + +import { + defaultValueCtx, + Editor, + EditorStatus, + editorViewCtx, + editorViewOptionsCtx, + rootCtx, + serializerCtx, +} from '@milkdown/core' +import { clipboard } from '@milkdown/plugin-clipboard' +import { history } from '@milkdown/plugin-history' +import { indent } from '@milkdown/plugin-indent' +import { listener, listenerCtx } from '@milkdown/plugin-listener' +import { commonmark } from '@milkdown/preset-commonmark' +import { gfm } from '@milkdown/preset-gfm' +import { InputRule } from '@milkdown/prose/inputrules' +import { $inputRule, $node, $remark, $view, replaceAll } from '@milkdown/utils' + +import { useIsUnMounted } from '~/hooks/common/use-is-unmounted' + +import styles from './index.module.css' +import { attacher } from './plugins/strike' + +const Container = (props) => { + const { contentRef, node, view, setAttrs } = useNodeViewContext() + console.log('aaaaa', useNodeViewContext()) + return ( + + ) +} + +const remarkDirective = $remark( + 'directive', + () => directive, +) as any as MilkdownPlugin + +const line = $remark('line', () => attacher()) as any as MilkdownPlugin + +const directiveGird = $node('grid', (ctx) => ({ + group: 'block', + atom: true, + isolating: true, + marks: '', + attrs: { + cols: { default: null }, + rows: { default: null }, + }, + + parseMarkdown: { + match: (node) => { + console.log(node, 'node') + return node.type === 'containerDirective' && node.name === 'grid' + }, + runner: (state, node, type) => { + state.addNode(type, { ...node.attributes }) + }, + }, + toMarkdown: { + match: (node) => node.type.name === 'grid', + runner: (state, node) => { + state.addNode('containerDirective', undefined, undefined, { + name: 'grid', + attributes: { ...node.attrs }, + }) + }, + }, +})) + +const directiveNode = $node('iframe', (ctx) => ({ + group: 'block', + atom: true, + isolating: true, + marks: '', + attrs: { + src: { default: null }, + }, + // parseDOM: [ + // { + // tag: 'iframe', + // getAttrs: (dom) => ({ + // src: (dom as HTMLElement).getAttribute('src'), + // }), + // }, + // ], + + // toDOM: (node) => { + // const $button = document.createElement('button') + // $button.innerHTML = node.attrs.src + // $button.onclick = (e) => { + // const edtior = ctx.get(editorViewCtx) + // const state = edtior.state + // state.doc.descendants((node, pos) => { + // console.log(node, 'node') + + // if (node.type.name === 'iframe') { + // const { tr } = state + // tr.replaceWith( + // pos, + // pos + node.nodeSize, + // node.type.create({ + // src: `https://saul-mirone.github.io?${Math.random()}`, + // }), + // ) + // edtior.dispatch(tr) + // return false + // } + // }) + // } + // return $button as InstanceType + // // return [ + // // $button, + // // { + // // ...node.attrs, + + // // contenteditable: false, + // // onclick() { + // // return console.log(node, 'node') + // // }, + // // }, + // // 'aa', + // // ] as const + // }, + + parseMarkdown: { + match: (node) => { + console.log(node, 'node') + return node.type === 'leafDirective' && node.name === 'iframe' + }, + runner: (state, node, type) => { + state.addNode(type, { src: (node.attributes as { src: string }).src }) + }, + }, + toMarkdown: { + match: (node) => node.type.name === 'iframe', + runner: (state, node) => { + state.addNode('leafDirective', undefined, undefined, { + name: 'iframe', + attributes: { src: node.attrs.src }, + }) + }, + }, +})) +const inputRule = $inputRule( + (ctx) => + new InputRule( + /::iframe\{src="(?[^"]+)?"?\}/, + (state, match, start, end) => { + const [okay, src = ''] = match + const { tr } = state + if (okay) { + tr.replaceWith( + start - 1, + end, + directiveNode.type(ctx).create({ src }), + ) + } + + return tr + }, + ), +) + +export interface MilkdownProps { + initialMarkdown?: string + readonly?: boolean + onBlur?(): void + onChange?(e: { target: { value: string } }): void + onMarkdownChange?(markdown: string): void + onCreated?(): void +} + +export interface MilkdownRef { + getMarkdown(): string | undefined + setMarkdown(markdown: string): void +} + +export const MilkdownEditor = forwardRef( + (props, ref) => { + return ( + + + + + + ) + }, +) + +MilkdownEditor.displayName = 'MilkdownEditor' + +const MilkdownEditorImpl = forwardRef( + (props, ref) => { + const { initialMarkdown } = props + + const editorCtxRef = useRef[0]>() + const editorRef = useRef() + const getMarkdown = useCallback( + () => + editorRef.current?.action((ctx) => { + const editorView = ctx.get(editorViewCtx) + const serializer = ctx.get(serializerCtx) + return serializer(editorView.state.doc) + }), + [], + ) + + const nodeViewFactory = useNodeViewFactory() + + nodeViewFactory({ + component: Container, + }) + + const { get } = useEditor((root) => { + const editor = Editor.make() + editorRef.current = editor + + return editor + .config((ctx) => { + editorCtxRef.current = ctx + + ctx.set(rootCtx, root) + ctx.set(defaultValueCtx, initialMarkdown || '') + editorCtxRef.current.update(editorViewOptionsCtx, (ctx) => ({ + ...ctx, + editable: () => !props.readonly, + })) + + ctx + .get(listenerCtx) + .markdownUpdated((ctx, markdown) => { + if (isUnMounted.current) return + + props.onMarkdownChange?.(markdown) + props.onChange?.({ target: { value: markdown } }) + }) + .blur(() => { + props.onBlur?.() + }) + }) + .use(commonmark) + .use(listener) + .use(clipboard) + .use(history) + .use(indent) + .use(gfm) + .use([remarkDirective, line, directiveNode, directiveGird, inputRule]) + .use( + $view(directiveNode, () => + nodeViewFactory({ + component: Container, + }), + ), + ) + .use( + $view(directiveGird, () => + nodeViewFactory({ + component: Container, + }), + ), + ) + .onStatusChange((o) => { + if (o === EditorStatus.Created) { + props.onCreated?.() + } + }) + }, []) + + const setMarkdown = useCallback( + (markdown: string) => { + get()?.action(replaceAll(markdown)) + }, + [get], + ) + + useImperativeHandle(ref, () => ({ + getMarkdown, + setMarkdown, + })) + + const isUnMounted = useIsUnMounted() + + const id = useId() + return ( +
+ +
+ ) + }, +) +MilkdownEditorImpl.displayName = 'MilkdownEditorImpl' diff --git a/src/components/modules/dashboard/editor/Milkdown/index.module.css b/src/components/ui/editor/Milkdown/index.module.css similarity index 100% rename from src/components/modules/dashboard/editor/Milkdown/index.module.css rename to src/components/ui/editor/Milkdown/index.module.css diff --git a/src/components/modules/dashboard/editor/Milkdown/index.ts b/src/components/ui/editor/Milkdown/index.ts similarity index 100% rename from src/components/modules/dashboard/editor/Milkdown/index.ts rename to src/components/ui/editor/Milkdown/index.ts diff --git a/src/components/ui/editor/Milkdown/plugins/strike.ts b/src/components/ui/editor/Milkdown/plugins/strike.ts new file mode 100644 index 0000000000..6db5a4d995 --- /dev/null +++ b/src/components/ui/editor/Milkdown/plugins/strike.ts @@ -0,0 +1,33 @@ +import { visit } from 'unist-util-visit' + +export function attacher() { + return transformer + + function transformer(tree) { + console.log('tree', tree) + visit(tree, 'text', (node, index, parent) => { + console.log('texdt', node) + const value = node.value + const matches = value.match(/~~(.*?)~~/) + if (matches) { + const before = value.slice(0, matches.index) + const after = value.slice(matches.index + matches[0].length) + const strikethrough = { + type: 'delete', + children: [{ type: 'text', value: matches[1] }], + } + + // Replace current node with multiple nodes if necessary + const nodes = [] + if (before) { + nodes.push({ type: 'text', value: before }) + } + nodes.push(strikethrough) + if (after) { + nodes.push({ type: 'text', value: after }) + } + parent.children.splice(index, 1, ...nodes) + } + }) + } +} diff --git a/src/components/ui/editor/index.demo.tsx b/src/components/ui/editor/index.demo.tsx new file mode 100644 index 0000000000..bb71e5f2d8 --- /dev/null +++ b/src/components/ui/editor/index.demo.tsx @@ -0,0 +1,60 @@ +import type { DocumentComponent } from 'storybook/typings' + +import { MilkdownEditor } from './Milkdown' + +// :::warning +// _here be dragons_ +// ::: + +// :::banner {error} +// _here be dragons_ +// ::: + +// :::gallery +// https://loremflickr.com/640/480/city?1 +// https://loremflickr.com/640/480/city?2 +// https://loremflickr.com/640/480/city?3 +// ![](https://loremflickr.com/640/480/city?4 'Image') +// ::: + +export const EditorDemo: DocumentComponent = () => { + return ( + + ) +} + +EditorDemo.meta = { + title: 'Editor', +} diff --git a/src/components/modules/dashboard/editor/index.ts b/src/components/ui/editor/index.ts similarity index 100% rename from src/components/modules/dashboard/editor/index.ts rename to src/components/ui/editor/index.ts diff --git a/storybook/package.json b/storybook/package.json index 564e048e04..b4224a7b9b 100644 --- a/storybook/package.json +++ b/storybook/package.json @@ -9,6 +9,7 @@ "postcss-import": "^16.0.0", "react-error-boundary": "4.0.12", "react-router-dom": "6.21.3", + "unist-util-visit": "5.0.0", "vite": "5.0.12", "vite-plugin-restart": "0.4.0" }, diff --git a/storybook/pnpm-lock.yaml b/storybook/pnpm-lock.yaml index b07a52ff34..c7dcee6987 100644 --- a/storybook/pnpm-lock.yaml +++ b/storybook/pnpm-lock.yaml @@ -20,6 +20,9 @@ dependencies: react-router-dom: specifier: 6.21.3 version: 6.21.3(react-dom@18.2.0)(react@18.2.0) + unist-util-visit: + specifier: 5.0.0 + version: 5.0.0 vite: specifier: 5.0.12 version: 5.0.12 @@ -944,7 +947,6 @@ packages: /@types/unist@3.0.2: resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} - dev: true /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} @@ -2305,7 +2307,6 @@ packages: resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} dependencies: '@types/unist': 3.0.2 - dev: true /unist-util-position-from-estree@2.0.0: resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} @@ -2337,7 +2338,6 @@ packages: dependencies: '@types/unist': 3.0.2 unist-util-is: 6.0.0 - dev: true /unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} @@ -2345,7 +2345,6 @@ packages: '@types/unist': 3.0.2 unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 - dev: true /unplugin-macros@0.9.2(rollup@4.9.5): resolution: {integrity: sha512-cWIpt6Rwovpwdu3DRV0Uqd5wpdLEz3pWJ36PMm6bS8WPQxawZ6NG2eEVo3agBvcj/6FATllWesO/nJ8DISgmrw==} diff --git a/storybook/vite.config.mts.timestamp-1706716056463-9580bc4ee8dca.mjs b/storybook/vite.config.mts.timestamp-1706716056463-9580bc4ee8dca.mjs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/storybook/vite.config.mts.timestamp-1706716345357-37f068121814c.mjs b/storybook/vite.config.mts.timestamp-1706716345357-37f068121814c.mjs new file mode 100644 index 0000000000..5fd2051938 --- /dev/null +++ b/storybook/vite.config.mts.timestamp-1706716345357-37f068121814c.mjs @@ -0,0 +1,55 @@ +// vite.config.mts +import { readFileSync } from "node:fs"; +import path, { resolve } from "node:path"; +import react from "file:///Users/innei/git/innei-repo/mx-space/sprightly/storybook/node_modules/.pnpm/@vitejs+plugin-react@4.2.1_vite@5.0.12/node_modules/@vitejs/plugin-react/dist/index.mjs"; +import { parse } from "file:///Users/innei/git/innei-repo/mx-space/sprightly/node_modules/.pnpm/dotenv@16.4.1/node_modules/dotenv/lib/main.js"; +import Macros from "file:///Users/innei/git/innei-repo/mx-space/sprightly/storybook/node_modules/.pnpm/unplugin-macros@0.9.2_rollup@4.9.5/node_modules/unplugin-macros/dist/index.mjs"; +import { defineConfig } from "file:///Users/innei/git/innei-repo/mx-space/sprightly/storybook/node_modules/.pnpm/vite@5.0.12/node_modules/vite/dist/node/index.js"; +import ViteRestart from "file:///Users/innei/git/innei-repo/mx-space/sprightly/storybook/node_modules/.pnpm/vite-plugin-restart@0.4.0_vite@5.0.12/node_modules/vite-plugin-restart/dist/index.js"; +import tsConfigPaths from "file:///Users/innei/git/innei-repo/mx-space/sprightly/storybook/node_modules/.pnpm/vite-tsconfig-paths@4.3.1_vite@5.0.12/node_modules/vite-tsconfig-paths/dist/index.mjs"; +import mdx from "file:///Users/innei/git/innei-repo/mx-space/sprightly/storybook/node_modules/.pnpm/@mdx-js+rollup@3.0.0_rollup@4.9.5/node_modules/@mdx-js/rollup/index.js"; +var __vite_injected_original_import_meta_url = "file:///Users/innei/git/innei-repo/mx-space/sprightly/storybook/vite.config.mts"; +var __dirname = new URL(".", __vite_injected_original_import_meta_url).pathname; +var env = parse(readFileSync(path.resolve(__dirname, "../.env"))); +var options = { + // See https://mdxjs.com/advanced/plugins + remarkPlugins: [ + // E.g. `remark-frontmatter` + ], + rehypePlugins: [] +}; +var vite_config_default = defineConfig({ + plugins: [ + Macros.vite(), + react(), + tsConfigPaths(), + mdx(options), + ViteRestart({ + restart: ["../**/index.demo.tsx", "../**/index.demo.mdx"] + }) + ], + define: { + __ROOT__: `"${__dirname}"`, + __COMPONENT_ROOT__: `"${resolve(__dirname, "..")}"`, + "process.env": { ...env } + }, + base: "", + resolve: { + alias: { + "next/image": resolve(__dirname, "./mock-packages/next_image"), + "next/link": resolve(__dirname, "./mock-packages/next_link"), + "next/dynamic": resolve(__dirname, "./mock-packages/next_dynamic"), + "next/navigation": resolve(__dirname, "./mock-packages/next_navigation"), + "~": resolve(__dirname, "../src") + } + }, + optimizeDeps: { + esbuildOptions: { + plugins: [Macros.esbuild()] + } + } +}); +export { + vite_config_default as default +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcubXRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL2lubmVpL2dpdC9pbm5laS1yZXBvL214LXNwYWNlL3NwcmlnaHRseS9zdG9yeWJvb2tcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9Vc2Vycy9pbm5laS9naXQvaW5uZWktcmVwby9teC1zcGFjZS9zcHJpZ2h0bHkvc3Rvcnlib29rL3ZpdGUuY29uZmlnLm10c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vVXNlcnMvaW5uZWkvZ2l0L2lubmVpLXJlcG8vbXgtc3BhY2Uvc3ByaWdodGx5L3N0b3J5Ym9vay92aXRlLmNvbmZpZy5tdHNcIjtpbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdub2RlOmZzJ1xuaW1wb3J0IHBhdGgsIHsgcmVzb2x2ZSB9IGZyb20gJ25vZGU6cGF0aCdcbmltcG9ydCByZWFjdCBmcm9tICdAdml0ZWpzL3BsdWdpbi1yZWFjdCdcbmltcG9ydCB7IHBhcnNlIH0gZnJvbSAnZG90ZW52J1xuaW1wb3J0IE1hY3JvcyBmcm9tICd1bnBsdWdpbi1tYWNyb3MnXG5pbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tICd2aXRlJ1xuaW1wb3J0IFZpdGVSZXN0YXJ0IGZyb20gJ3ZpdGUtcGx1Z2luLXJlc3RhcnQnXG5pbXBvcnQgdHNDb25maWdQYXRocyBmcm9tICd2aXRlLXRzY29uZmlnLXBhdGhzJ1xuXG5pbXBvcnQgbWR4IGZyb20gJ0BtZHgtanMvcm9sbHVwJ1xuXG5jb25zdCBfX2Rpcm5hbWUgPSBuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKS5wYXRobmFtZVxuY29uc3QgZW52ID0gcGFyc2UocmVhZEZpbGVTeW5jKHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuLi8uZW52JykpKVxuXG4vLyBgb3B0aW9uc2AgYXJlIHBhc3NlZCB0byBgQG1keC1qcy9tZHhgXG5jb25zdCBvcHRpb25zID0ge1xuICAvLyBTZWUgaHR0cHM6Ly9tZHhqcy5jb20vYWR2YW5jZWQvcGx1Z2luc1xuICByZW1hcmtQbHVnaW5zOiBbXG4gICAgLy8gRS5nLiBgcmVtYXJrLWZyb250bWF0dGVyYFxuICBdLFxuICByZWh5cGVQbHVnaW5zOiBbXSxcbn1cblxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZyh7XG4gIHBsdWdpbnM6IFtcbiAgICBNYWNyb3Mudml0ZSgpLFxuICAgIHJlYWN0KCksXG4gICAgdHNDb25maWdQYXRocygpLFxuICAgIG1keChvcHRpb25zKSxcbiAgICBWaXRlUmVzdGFydCh7XG4gICAgICByZXN0YXJ0OiBbJy4uLyoqL2luZGV4LmRlbW8udHN4JywgJy4uLyoqL2luZGV4LmRlbW8ubWR4J10sXG4gICAgfSksXG4gIF0sXG5cbiAgZGVmaW5lOiB7XG4gICAgX19ST09UX186IGBcIiR7X19kaXJuYW1lfVwiYCxcbiAgICBfX0NPTVBPTkVOVF9ST09UX186IGBcIiR7cmVzb2x2ZShfX2Rpcm5hbWUsICcuLicpfVwiYCxcbiAgICAncHJvY2Vzcy5lbnYnOiB7IC4uLmVudiB9LFxuICB9LFxuICBiYXNlOiAnJyxcbiAgcmVzb2x2ZToge1xuICAgIGFsaWFzOiB7XG4gICAgICAnbmV4dC9pbWFnZSc6IHJlc29sdmUoX19kaXJuYW1lLCAnLi9tb2NrLXBhY2thZ2VzL25leHRfaW1hZ2UnKSxcbiAgICAgICduZXh0L2xpbmsnOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vbW9jay1wYWNrYWdlcy9uZXh0X2xpbmsnKSxcbiAgICAgICduZXh0L2R5bmFtaWMnOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vbW9jay1wYWNrYWdlcy9uZXh0X2R5bmFtaWMnKSxcbiAgICAgICduZXh0L25hdmlnYXRpb24nOiByZXNvbHZlKF9fZGlybmFtZSwgJy4vbW9jay1wYWNrYWdlcy9uZXh0X25hdmlnYXRpb24nKSxcbiAgICAgICd+JzogcmVzb2x2ZShfX2Rpcm5hbWUsICcuLi9zcmMnKSxcbiAgICB9LFxuICB9LFxuXG4gIG9wdGltaXplRGVwczoge1xuICAgIGVzYnVpbGRPcHRpb25zOiB7XG4gICAgICBwbHVnaW5zOiBbTWFjcm9zLmVzYnVpbGQoKV0sXG4gICAgfSxcbiAgfSxcbn0pXG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQTRWLFNBQVMsb0JBQW9CO0FBQ3pYLE9BQU8sUUFBUSxlQUFlO0FBQzlCLE9BQU8sV0FBVztBQUNsQixTQUFTLGFBQWE7QUFDdEIsT0FBTyxZQUFZO0FBQ25CLFNBQVMsb0JBQW9CO0FBQzdCLE9BQU8saUJBQWlCO0FBQ3hCLE9BQU8sbUJBQW1CO0FBRTFCLE9BQU8sU0FBUztBQVR5TSxJQUFNLDJDQUEyQztBQVcxUSxJQUFNLFlBQVksSUFBSSxJQUFJLEtBQUssd0NBQWUsRUFBRTtBQUNoRCxJQUFNLE1BQU0sTUFBTSxhQUFhLEtBQUssUUFBUSxXQUFXLFNBQVMsQ0FBQyxDQUFDO0FBR2xFLElBQU0sVUFBVTtBQUFBO0FBQUEsRUFFZCxlQUFlO0FBQUE7QUFBQSxFQUVmO0FBQUEsRUFDQSxlQUFlLENBQUM7QUFDbEI7QUFHQSxJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixTQUFTO0FBQUEsSUFDUCxPQUFPLEtBQUs7QUFBQSxJQUNaLE1BQU07QUFBQSxJQUNOLGNBQWM7QUFBQSxJQUNkLElBQUksT0FBTztBQUFBLElBQ1gsWUFBWTtBQUFBLE1BQ1YsU0FBUyxDQUFDLHdCQUF3QixzQkFBc0I7QUFBQSxJQUMxRCxDQUFDO0FBQUEsRUFDSDtBQUFBLEVBRUEsUUFBUTtBQUFBLElBQ04sVUFBVSxJQUFJLFNBQVM7QUFBQSxJQUN2QixvQkFBb0IsSUFBSSxRQUFRLFdBQVcsSUFBSSxDQUFDO0FBQUEsSUFDaEQsZUFBZSxFQUFFLEdBQUcsSUFBSTtBQUFBLEVBQzFCO0FBQUEsRUFDQSxNQUFNO0FBQUEsRUFDTixTQUFTO0FBQUEsSUFDUCxPQUFPO0FBQUEsTUFDTCxjQUFjLFFBQVEsV0FBVyw0QkFBNEI7QUFBQSxNQUM3RCxhQUFhLFFBQVEsV0FBVywyQkFBMkI7QUFBQSxNQUMzRCxnQkFBZ0IsUUFBUSxXQUFXLDhCQUE4QjtBQUFBLE1BQ2pFLG1CQUFtQixRQUFRLFdBQVcsaUNBQWlDO0FBQUEsTUFDdkUsS0FBSyxRQUFRLFdBQVcsUUFBUTtBQUFBLElBQ2xDO0FBQUEsRUFDRjtBQUFBLEVBRUEsY0FBYztBQUFBLElBQ1osZ0JBQWdCO0FBQUEsTUFDZCxTQUFTLENBQUMsT0FBTyxRQUFRLENBQUM7QUFBQSxJQUM1QjtBQUFBLEVBQ0Y7QUFDRixDQUFDOyIsCiAgIm5hbWVzIjogW10KfQo= diff --git a/storybook/vite.config.mts.timestamp-1706716552729-c966d43f7c18e.mjs b/storybook/vite.config.mts.timestamp-1706716552729-c966d43f7c18e.mjs new file mode 100644 index 0000000000..e69de29bb2 From 49b3dfe40dc73a8068431160aa9d1e544a7526c7 Mon Sep 17 00:00:00 2001 From: Innei Date: Thu, 1 Feb 2024 17:16:14 +0800 Subject: [PATCH 2/6] feat: block edit Signed-off-by: Innei --- package.json | 3 + pnpm-lock.yaml | 53 + .../ui/editor/Milkdown/MilkdownEditor.tsx | 197 +- src/components/ui/editor/Milkdown/ctx.tsx | 10 + .../ui/editor/Milkdown/plugins/Blockquote.tsx | 24 + .../ui/editor/Milkdown/plugins/CodeBlock.tsx | 191 ++ .../ui/editor/Milkdown/plugins/Mermaid.tsx | 93 + .../ui/editor/Milkdown/plugins/index.ts | 19 + .../ui/editor/Milkdown/plugins/strike.ts | 33 - .../ui/editor/Milkdown/plugins/test.tsx | 98 + .../ui/editor/Milkdown/plugins/types.ts | 6 + src/components/ui/editor/index.demo.tsx | 53 +- src/components/ui/excalidraw/Excalidraw.tsx | 120 +- src/components/ui/markdown/customize.md | 2 + src/components/ui/modal/stacked/modal.tsx | 6 +- src/components/ui/modal/stacked/types.tsx | 2 + src/providers/root/index.tsx | 38 +- storybook/package.json | 1 - storybook/pnpm-lock.yaml | 2225 +++++++++++++---- 19 files changed, 2428 insertions(+), 746 deletions(-) create mode 100644 src/components/ui/editor/Milkdown/ctx.tsx create mode 100644 src/components/ui/editor/Milkdown/plugins/Blockquote.tsx create mode 100644 src/components/ui/editor/Milkdown/plugins/CodeBlock.tsx create mode 100644 src/components/ui/editor/Milkdown/plugins/Mermaid.tsx create mode 100644 src/components/ui/editor/Milkdown/plugins/index.ts delete mode 100644 src/components/ui/editor/Milkdown/plugins/strike.ts create mode 100644 src/components/ui/editor/Milkdown/plugins/test.tsx create mode 100644 src/components/ui/editor/Milkdown/plugins/types.ts diff --git a/package.json b/package.json index d1ed150844..ce1634cb72 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@milkdown/core": "7.3.3", "@milkdown/ctx": "7.3.3", "@milkdown/plugin-clipboard": "7.3.3", + "@milkdown/plugin-diagram": "^7.3.3", "@milkdown/plugin-history": "7.3.3", "@milkdown/plugin-indent": "7.3.3", "@milkdown/plugin-listener": "7.3.3", @@ -102,11 +103,13 @@ "react-tweet": "3.2.0", "react-wrap-balancer": "1.1.0", "remark-directive": "3.0.0", + "remark-github-alerts": "^0.0.4", "remove-markdown": "0.5.0", "server-only": "^0.0.1", "socket.io-client": "4.7.4", "tailwind-merge": "2.2.1", "unidata.js": "0.8.0", + "unified": "^11.0.4", "uniqolor": "1.1.1", "unist-util-visit": "5.0.0", "use-context-selector": "1.4.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a0963fbe73..68c2390cf3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ dependencies: '@milkdown/plugin-clipboard': specifier: 7.3.3 version: 7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3) + '@milkdown/plugin-diagram': + specifier: ^7.3.3 + version: 7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3) '@milkdown/plugin-history': specifier: 7.3.3 version: 7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3) @@ -215,6 +218,9 @@ dependencies: remark-directive: specifier: 3.0.0 version: 3.0.0 + remark-github-alerts: + specifier: ^0.0.4 + version: 0.0.4(@types/mdast@4.0.3)(unified@11.0.4) remove-markdown: specifier: 0.5.0 version: 0.5.0 @@ -230,6 +236,9 @@ dependencies: unidata.js: specifier: 0.8.0 version: 0.8.0(typescript@5.3.3) + unified: + specifier: ^11.0.4 + version: 11.0.4 uniqolor: specifier: 1.1.1 version: 1.1.1 @@ -1684,6 +1693,29 @@ packages: - '@milkdown/transformer' dev: false + /@milkdown/plugin-diagram@7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3): + resolution: {integrity: sha512-MFTs+5YcW2wol+AiQXGM1IqTLZDj8H7V1rElGGaxMDtctDm2t8P6Pe25prXB7mxosPndrx60/fSHTAO+YU09pg==} + peerDependencies: + '@milkdown/core': ^7.2.0 + '@milkdown/ctx': ^7.2.0 + '@milkdown/prose': ^7.2.0 + '@milkdown/transformer': ^7.2.0 + dependencies: + '@milkdown/core': 7.3.3(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3) + '@milkdown/ctx': 7.3.3 + '@milkdown/exception': 7.3.3 + '@milkdown/prose': 7.3.3 + '@milkdown/transformer': 7.3.3(@milkdown/prose@7.3.3) + '@milkdown/utils': 7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3) + '@types/dompurify': 3.0.5 + mermaid: 10.7.0 + nanoid: 5.0.4 + tslib: 2.6.2 + unist-util-visit: 5.0.0 + transitivePeerDependencies: + - supports-color + dev: false + /@milkdown/plugin-history@7.3.3(@milkdown/core@7.3.3)(@milkdown/ctx@7.3.3)(@milkdown/prose@7.3.3)(@milkdown/transformer@7.3.3): resolution: {integrity: sha512-f3lokMDzZUIiNwIZ4V5LI6gnFgjgncl6CdgzWimNhU5ar9ptAYjn3P224UDUGRg+QUjqI9o9oX+68JNy3KC5vw==} peerDependencies: @@ -2948,6 +2980,12 @@ packages: '@types/ms': 0.7.34 dev: false + /@types/dompurify@3.0.5: + resolution: {integrity: sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==} + dependencies: + '@types/trusted-types': 2.0.7 + dev: false + /@types/express-serve-static-core@4.17.41: resolution: {integrity: sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==} dependencies: @@ -3148,6 +3186,10 @@ packages: '@types/node': 20.11.10 dev: false + /@types/trusted-types@2.0.7: + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + dev: false + /@types/unist@2.0.10: resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} dev: false @@ -8306,6 +8348,17 @@ packages: - supports-color dev: false + /remark-github-alerts@0.0.4(@types/mdast@4.0.3)(unified@11.0.4): + resolution: {integrity: sha512-cGO8CrGb4Vvawn71inAv6VNRL8CKkHYwKpI91ZvbuLhW8W5EkLReQOjqsnj18Hw99X5u44hKyYssOzXLlZdGHQ==} + peerDependencies: + '@types/mdast': ^4.0.0 + unified: ^11.0.0 + dependencies: + '@types/mdast': 4.0.3 + unified: 11.0.4 + unist-util-visit: 5.0.0 + dev: false + /remark-inline-links@7.0.0: resolution: {integrity: sha512-4uj1pPM+F495ySZhTIB6ay2oSkTsKgmYaKk/q5HIdhX2fuyLEegpjWa0VdJRJ01sgOqAFo7MBKdDUejIYBMVMQ==} dependencies: diff --git a/src/components/ui/editor/Milkdown/MilkdownEditor.tsx b/src/components/ui/editor/Milkdown/MilkdownEditor.tsx index 3f8d2012a6..87b2ed5985 100644 --- a/src/components/ui/editor/Milkdown/MilkdownEditor.tsx +++ b/src/components/ui/editor/Milkdown/MilkdownEditor.tsx @@ -1,7 +1,6 @@ import { Milkdown, MilkdownProvider, useEditor } from '@milkdown/react' import { ProsemirrorAdapterProvider, - useNodeViewContext, useNodeViewFactory, } from '@prosemirror-adapter/react' import { @@ -11,9 +10,7 @@ import { useImperativeHandle, useRef, } from 'react' -import directive from 'remark-directive' import type { Config } from '@milkdown/core' -import type { MilkdownPlugin } from '@milkdown/ctx' import { defaultValueCtx, @@ -30,177 +27,13 @@ import { indent } from '@milkdown/plugin-indent' import { listener, listenerCtx } from '@milkdown/plugin-listener' import { commonmark } from '@milkdown/preset-commonmark' import { gfm } from '@milkdown/preset-gfm' -import { InputRule } from '@milkdown/prose/inputrules' -import { $inputRule, $node, $remark, $view, replaceAll } from '@milkdown/utils' +import { replaceAll } from '@milkdown/utils' import { useIsUnMounted } from '~/hooks/common/use-is-unmounted' +import { setEditorCtx } from './ctx' import styles from './index.module.css' -import { attacher } from './plugins/strike' - -const Container = (props) => { - const { contentRef, node, view, setAttrs } = useNodeViewContext() - console.log('aaaaa', useNodeViewContext()) - return ( - - ) -} - -const remarkDirective = $remark( - 'directive', - () => directive, -) as any as MilkdownPlugin - -const line = $remark('line', () => attacher()) as any as MilkdownPlugin - -const directiveGird = $node('grid', (ctx) => ({ - group: 'block', - atom: true, - isolating: true, - marks: '', - attrs: { - cols: { default: null }, - rows: { default: null }, - }, - - parseMarkdown: { - match: (node) => { - console.log(node, 'node') - return node.type === 'containerDirective' && node.name === 'grid' - }, - runner: (state, node, type) => { - state.addNode(type, { ...node.attributes }) - }, - }, - toMarkdown: { - match: (node) => node.type.name === 'grid', - runner: (state, node) => { - state.addNode('containerDirective', undefined, undefined, { - name: 'grid', - attributes: { ...node.attrs }, - }) - }, - }, -})) - -const directiveNode = $node('iframe', (ctx) => ({ - group: 'block', - atom: true, - isolating: true, - marks: '', - attrs: { - src: { default: null }, - }, - // parseDOM: [ - // { - // tag: 'iframe', - // getAttrs: (dom) => ({ - // src: (dom as HTMLElement).getAttribute('src'), - // }), - // }, - // ], - - // toDOM: (node) => { - // const $button = document.createElement('button') - // $button.innerHTML = node.attrs.src - // $button.onclick = (e) => { - // const edtior = ctx.get(editorViewCtx) - // const state = edtior.state - // state.doc.descendants((node, pos) => { - // console.log(node, 'node') - - // if (node.type.name === 'iframe') { - // const { tr } = state - // tr.replaceWith( - // pos, - // pos + node.nodeSize, - // node.type.create({ - // src: `https://saul-mirone.github.io?${Math.random()}`, - // }), - // ) - // edtior.dispatch(tr) - // return false - // } - // }) - // } - // return $button as InstanceType - // // return [ - // // $button, - // // { - // // ...node.attrs, - - // // contenteditable: false, - // // onclick() { - // // return console.log(node, 'node') - // // }, - // // }, - // // 'aa', - // // ] as const - // }, - - parseMarkdown: { - match: (node) => { - console.log(node, 'node') - return node.type === 'leafDirective' && node.name === 'iframe' - }, - runner: (state, node, type) => { - state.addNode(type, { src: (node.attributes as { src: string }).src }) - }, - }, - toMarkdown: { - match: (node) => node.type.name === 'iframe', - runner: (state, node) => { - state.addNode('leafDirective', undefined, undefined, { - name: 'iframe', - attributes: { src: node.attrs.src }, - }) - }, - }, -})) -const inputRule = $inputRule( - (ctx) => - new InputRule( - /::iframe\{src="(?[^"]+)?"?\}/, - (state, match, start, end) => { - const [okay, src = ''] = match - const { tr } = state - if (okay) { - tr.replaceWith( - start - 1, - end, - directiveNode.type(ctx).create({ src }), - ) - } - - return tr - }, - ), -) +import { createPlugins } from './plugins' export interface MilkdownProps { initialMarkdown?: string @@ -248,16 +81,13 @@ const MilkdownEditorImpl = forwardRef( const nodeViewFactory = useNodeViewFactory() - nodeViewFactory({ - component: Container, - }) - const { get } = useEditor((root) => { const editor = Editor.make() editorRef.current = editor return editor .config((ctx) => { + setEditorCtx(ctx) editorCtxRef.current = ctx ctx.set(rootCtx, root) @@ -272,6 +102,7 @@ const MilkdownEditorImpl = forwardRef( .markdownUpdated((ctx, markdown) => { if (isUnMounted.current) return + console.log('markdown', markdown) props.onMarkdownChange?.(markdown) props.onChange?.({ target: { value: markdown } }) }) @@ -285,21 +116,8 @@ const MilkdownEditorImpl = forwardRef( .use(history) .use(indent) .use(gfm) - .use([remarkDirective, line, directiveNode, directiveGird, inputRule]) - .use( - $view(directiveNode, () => - nodeViewFactory({ - component: Container, - }), - ), - ) - .use( - $view(directiveGird, () => - nodeViewFactory({ - component: Container, - }), - ), - ) + .use(createPlugins({ nodeViewFactory })) + .onStatusChange((o) => { if (o === EditorStatus.Created) { props.onCreated?.() @@ -329,4 +147,5 @@ const MilkdownEditorImpl = forwardRef( ) }, ) + MilkdownEditorImpl.displayName = 'MilkdownEditorImpl' diff --git a/src/components/ui/editor/Milkdown/ctx.tsx b/src/components/ui/editor/Milkdown/ctx.tsx new file mode 100644 index 0000000000..1bd074e36e --- /dev/null +++ b/src/components/ui/editor/Milkdown/ctx.tsx @@ -0,0 +1,10 @@ +import { atom, useAtomValue } from 'jotai' +import type { Ctx } from '@milkdown/ctx' + +import { jotaiStore } from '~/lib/store' + +export const editorCtxAtom = atom(null) + +export const useEditorCtx = () => useAtomValue(editorCtxAtom) + +export const setEditorCtx = (ctx: Ctx) => jotaiStore.set(editorCtxAtom, ctx) diff --git a/src/components/ui/editor/Milkdown/plugins/Blockquote.tsx b/src/components/ui/editor/Milkdown/plugins/Blockquote.tsx new file mode 100644 index 0000000000..c69cbe395b --- /dev/null +++ b/src/components/ui/editor/Milkdown/plugins/Blockquote.tsx @@ -0,0 +1,24 @@ +import { useNodeViewContext } from '@prosemirror-adapter/react' +import type { MilkdownPlugin } from '@milkdown/ctx' +import type { PluginCtx } from './types' + +import { blockquoteSchema } from '@milkdown/preset-commonmark' +import { $view } from '@milkdown/utils' + +const Blockquote = () => { + const { contentRef } = useNodeViewContext() + + return ( +
+ ) +} + +export const BlockquotePlugin: (pluginCtx: PluginCtx) => MilkdownPlugin[] = ({ + nodeViewFactory, +}) => [ + $view(blockquoteSchema.node, () => + nodeViewFactory({ + component: Blockquote, + }), + ), +] diff --git a/src/components/ui/editor/Milkdown/plugins/CodeBlock.tsx b/src/components/ui/editor/Milkdown/plugins/CodeBlock.tsx new file mode 100644 index 0000000000..a140c51b6f --- /dev/null +++ b/src/components/ui/editor/Milkdown/plugins/CodeBlock.tsx @@ -0,0 +1,191 @@ +import { useNodeViewContext } from '@prosemirror-adapter/react' +import { useEffect, useMemo, useRef } from 'react' +import { useForceUpdate } from 'framer-motion' +import type { MilkdownPlugin } from '@milkdown/ctx' +import type { NodeViewContext } from '@prosemirror-adapter/react' +import type { ModalContentPropsInternal } from '~/components/ui/modal' +import type { FC } from 'react' +import type { PluginCtx } from './types' + +import { serializeAsJSON } from '@excalidraw/excalidraw' +import { schemaCtx } from '@milkdown/core' +import { codeBlockSchema } from '@milkdown/preset-commonmark' +import { $view } from '@milkdown/utils' + +import { StyledButton } from '~/components/ui/button' +import { HighLighter } from '~/components/ui/code-highlighter' +import { Excalidraw } from '~/components/ui/excalidraw' +import { TextArea } from '~/components/ui/input' +import { useCurrentModal, useModalStack } from '~/components/ui/modal' +import { useUncontrolledInput } from '~/hooks/common/use-uncontrolled-input' + +import { useEditorCtx } from '../ctx' + +const CodeBlock = () => { + const { node } = useNodeViewContext() + + const language = node.attrs.language + const content = node.content.firstChild?.text || '' + + switch (language) { + case 'excalidraw': { + return + } + } + + return ( +
+ +
+ ) +} + +const NormalCodeBlock: FC<{ + content: string + language: string +}> = ({ content, language }) => { + const nodeCtx = useNodeViewContext() + + const modalStack = useModalStack() + + const handleEdit = () => { + const Content: FC = () => { + const [, getValue, ref] = + useUncontrolledInput(content) + return ( +
+